【问题标题】:Generate PDF of Protected Django Webpage with Attachments生成带有附件的受保护 Django 网页的 PDF
【发布时间】:2023-03-09 02:48:01
【问题描述】:

所以我正在尝试生成我在 django Web 应用程序中拥有的视图的 PDF。此视图受保护,这意味着用户必须登录并具有特定权限才能查看该页面。我还有一些附件(以FileFields 的形式存储在数据库中),我想将它们附加到 PDF 的末尾。

我已经阅读了大部分关于如何使用 pdfkitreportlab 从网页生成 PDF 的帖子,但由于某种原因,所有这些帖子对我来说都失败了。

目前,我得到的最接近的是使用pdfkit 成功生成页面的 PDF,但这需要我删除要求用户登录并拥有页面权限的限制,这实际上不是一个长期的选择。我发现了几篇讨论在受保护页面上打印 pdf 并提供登录信息的帖子,但我无法让其中任何一个工作。

我还没有找到任何关于如何包含附件的信息,并且真的不知道从哪里开始。

如果需要,我很乐意用更多信息或代码 sn-ps 来更新这个问题,但这里有很多活动部分,我不想让人们用无用的信息淹没。让我知道我是否应该提供任何其他信息,并提前感谢您的帮助。

【问题讨论】:

    标签: python django python-3.x pdf reportlab


    【解决方案1】:

    您可以使用pdfkit 来执行此操作。您可以使用 url 检索页面,pdfkit 将处理其余部分:

    pdfkit.from_url('http://website.com/somepage', 'somepage.pdf')
    

    您必须使用适当的标题正确访问该页面,因为它当然受到保护:

    options = {
        'cookie': [
            ('cookie-name1', 'cookie-value1'),
            ('cookie-name2', 'cookie-value2'),
        ]
    }
    
    pdfkit.from_url('http://website.com/somepage', 'somepage.pdf')
    `
    

    【讨论】:

    • 我有点困惑。使应用程序能够正确登录的选项对象的结构是什么样的?正如我在问题中指出的那样,我之前尝试过类似的方法,但无法使其正常工作。我正在使用内置的 django 用户验证。另外,您不必以某种方式将该选项对象传递给 pdfkit 吗?而且我仍然需要能够添加附件。
    【解决方案2】:

    如果您只是想保护它,您可以编写一个自定义身份验证后端,让您的服务器欺骗用户。方式过度杀戮,但它会解决您的问题,至少您可以了解自定义身份验证后端! (注意:您应该使用 HTTPS。)

    https://docs.djangoproject.com/en/1.11/topics/auth/customizing/#writing-an-authentication-backend

    1. app/auth_backends.py 中创建身份验证后端
    2. app.auth_backends.SpoofAuthBackend 后端添加到settings.py,这需要shared_secretuser_id
    3. 创建一个 URL 路由,如 url(r'^spoof-user/(?P<user_id>\d+)/$', 'app.views.spoof_user', name="spoof-user")
    4. 添加视图spoof_user,该视图必须同时调用django.contrib.auth.authenticate(调用上面#1 中的后端),并且在从authenticate(...) 获取用户后,您使用用户django.contrib.auth.login(request, user) 填充请求。最后,如果共享密钥错误,此视图应返回 HttpResponseForbidden 或将 HttpResponseRedirect 返回到您实际想要的 PDF URL(在通过 authenticatelogin 以编程方式登录到欺骗用户之后)。

    您可能希望使用 cache.set('spoof-user-%s' % user_id, RANDOM_STRING, 30) 之类的东西为每个请求创建一个随机密钥,它将共享密钥保留 30 秒以留出请求时间。然后执行pdf_response = requests.get("%s?shared_secret=1a2b3c&redirect_uri=/path/to/pdf/" % reverse('spoof-user', kwargs={'user_id': 1234}))。您的新视图将在身份验证后端测试提供的shared_secret,登录用户请求并执行重定向到request.GET.get('redirect_uri')

    【讨论】:

    • 我还要补充一点,我使用wkhtmltopdf 完全在服务器端生成所有 PDF,但能够欺骗用户对于某些项目可能很有用。例如,仅让管理员或帮助台人员能够登录并查看他们的项目以帮助解决支持问题等。
    • 我还刚刚上传了一个要点,显示了django-wkhtmltopdf 的用法:gist.github.com/pztrick/94a90908954bcdb5f672f00aa4d9b2de 请注意,您需要重构您的视图,以便它们将相同的context 字典传递给模板,而不是访问像@ 这样的东西987654345@.
    • 那个要点看起来更合理,并且类似于我正在研究的东西......我会用它来测试。关于如何附加附件的任何想法?
    • 嗨@Nealon!这是我的另一个项目的要点,它有几个功能:1)将 PDF 合并到单个 PDF 和 2)将 PDF 添加到 Zipfile 附件中。我的评论表明#1 已损坏,但由于此代码是很久以前编写的,现在可能已修复。 gist.github.com/pztrick/2e6bb623651079cb216c1e1b8b899253
    【解决方案3】:

    我搞定了!通过 PyPDF2 和 pdfkit 的结合,我得到了这个非常简单的工作。它适用于受保护的页面,因为 django 负责将完整的 html 作为字符串获取,我只是将其传递给 pdfkit。它还支持附加附件,但我怀疑(尽管我没有测试过)它是否适用于 pdf 以外的任何内容。

    from django.template.loader import get_template
    from PyPDF2 import PdfFileWriter, PdfFileReader
    import pdfkit
    
    def append_pdf(pdf, output):
        [output.addPage(pdf.getPage(page_num)) for page_num in range(pdf.numPages)]
    
    
    def render_to_pdf():
        t = get_template('app/template.html')
        c = {'context_data': context_data}
    
        html = t.render(c)
        pdfkit.from_string(html, 'path/to/file.pdf')
    
        output = PdfFileWriter()
        append_pdf(PdfFileReader(open('path/to/file.pdf', "rb")), output)
    
        attaches = Attachment.objects.all()
    
        for attach in attaches:
            append_pdf(PdfFileReader(open(attach.file.path, "rb")), output)
    
        output.write(open('path/to/file_with_attachments.pdf', "wb"))
    

    【讨论】:

    • 感谢您的解决方案。我能够在 Django 中将受保护的网页转换为 pdf。然而,该页面有 2 张图片没有出现在 pdf 中。我也有一个错误,指出加载文件失败:///relative/image/path.如何使用 django 确保图像也包含在 pdf 中
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    相关资源
    最近更新 更多