【问题标题】:"Need a valid file name!" xhtml2pdf with Django“需要一个有效的文件名!” xhtml2pdf 与 Django
【发布时间】:2018-12-19 15:03:09
【问题描述】:

我的问题是:我正在使用 xhtml2pdf 库从 html 创建一个 pdf 文件。创建 pdf 文件后,我使用 sendgrid API 通过电子邮件将文件发送给用户。但是,我无法将图像嵌入到 pdf 文件中,因为应用程序返回“需要有效的文件名!”信息。我在几个地方进行了研究,但找不到解决方案。使用的代码如下。

HTML 代码:

<img src="/static/media/logo.jpg" alt="Image">

python代码(将html转换为pdf):

def link_callback(uri, rel):
"""
Convert HTML URIs to absolute system paths so xhtml2pdf can access those
resources
"""
# use short variable names
sUrl = settings.STATIC_URL
mUrl = settings.MEDIA_URL
mRoot = settings.MEDIA_ROOT

# convert URIs to absolute system paths
if uri.startswith(mUrl):
    path = os.path.join(mRoot, uri.replace(mUrl, ""))

else:
    return uri  # handle absolute uri (ie: http://some.tld/foo.png)

# make sure that file exists
if not os.path.isfile(path):
        raise Exception(
            'media URI must start with %s or %s' % (sUrl, mUrl)
        )
return path

def render_to_pdf(template_source, context_dict={}):
    from io import BytesIO
    from django.http import HttpResponse
    from django.template.loader import get_template
    from xhtml2pdf import pisa

    template = get_template(template_source)
    html = template.render(context_dict)
    result = BytesIO()
    pdf = pisa.pisaDocument(BytesIO(html.encode("UTF-8")), result, 
                        link_callback=link_callback, encoding='UTF-8')

    if not pdf.err:
        return result.getvalue()
    return None

python 代码(通过电子邮件发送 pdf 文件):

def send_mail_template(subject, template_name, context, recipient_list, from_email=<email>, attachments=None):

sg = sendgrid.SendGridAPIClient(apikey=<apikey>)
sendgrid_from_email = Email(email=from_email, name=<name>)
message_html = render_to_string(template_name, context)
content = Content("text/html", message_html)

sendgrid_to_email = Email(recipient_list[0])
mail = Mail(sendgrid_from_email, subject, sendgrid_to_email, content)

try:
    if attachments is not None:
        for attachment in attachments:
            sendgrid_attachment = Attachment()
            sendgrid_attachment.content = base64.b64encode(attachment['file']).decode()
            sendgrid_attachment.content_id = attachment['filename']
            sendgrid_attachment.type = attachment['type']
            sendgrid_attachment.filename = attachment['filename']
            sendgrid_attachment.disposition = attachment['disposition']

            mail.add_attachment(sendgrid_attachment)
except Exception as err:
    print(err)

response = sg.client.mail.send.post(request_body=mail.get())

return response.status_code

错误:

Need a valid file name!
'<img alt="Image" src="/static/media/logo.jpg"/>'

【问题讨论】:

  • 一旦我也遇到了同样的问题,对我有用的是放置静态图像完整路径或上传到某个存储桶并放置 url。如果你找不到任何解决方案,你可以试试。
  • 谢谢@SergeyPugach。我把完整的路径,它的工作!但是,如果有人知道如何获取具有相对路径的图像,那对我来说会更好。
  • @SergeyPugach 请添加您的评论作为答案 - 它解决了我已经处理了两天的问题!
  • @Jesuisme 我已将其发布为答案。

标签: django python-3.x xhtml2pdf pisa


【解决方案1】:

似乎xhtml2pdf 在渲染位于模板旁边的图像时存在一些问题。为了解决这个问题,您可以尝试:

  1. 放置静态图片完整路径,如
  2. 将您的图片上传到某个存储桶并在src 中提供完整的网址。

【讨论】:

  • 如果 s3 存储桶是私有的,那么我如何访问图像?
  • @yasirkk 预签名网址
【解决方案2】:

我遇到了同样的错误

<img src={{ employee.photo.url }}>

当我使用路径而不是 url 时,错误消失了

<img src={{ employee.photo.path }}>

【讨论】:

    【解决方案3】:

    我遇到了同样的问题,我通过将完整路径放在图像标签中解决了它,因为 wkhtmltopdf 不支持相对路径。

    【讨论】:

      【解决方案4】:

      首先,你需要运行 python manage.py collectstatic,我确实有同样的错误

      【讨论】:

      • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
      【解决方案5】:

      我通过首先将其转换为 base64 格式,成功地在渲染为 pdf 的 Django 模板中实现了静态文件图像。

      首先,创建一个新的模板标签(归功于jsanchezsthis post):

      import base64
      from django import template
      from django.contrib.staticfiles.finders import find as find_static_file
      
      register = template.Library()
      
      @register.simple_tag
      def encode_static(path, encodign='base64', file_type='image'):
        try:
          file_path = find_static_file(path)
          ext = file_path.split('.')[-1]
          file_str = _get_file_data(file_path).decode('utf-8')
          return "data:{0}/{1};{2}, {3}".format(file_type, ext, encodign, file_str)
        except IOError:
          return ''
      
      def _get_file_data(file_path):
        with open(file_path, 'rb') as f:
          data = base64.b64encode(f.read())
          f.close()
          return data
      

      然后在pdf模板里面,就可以使用新创建的模板标签了:

      {% load encode_static %}
      
      <img alt="IMAGE" src="{% encode_static 'path/to/my/static/file.png' %}">
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-06-16
        • 2019-02-14
        • 1970-01-01
        • 2016-02-18
        • 1970-01-01
        • 2014-03-31
        • 2017-03-27
        • 2011-07-18
        相关资源
        最近更新 更多