响应未在 HTMX 中作为附件处理(即文件未下载)

问题描述 投票:0回答:2

我对 Django 相当陌生,但我已经被一个问题困扰好几天了。我一直在网上寻找答案但没有成功。

我有一个名为 CreateReportView 的视图,我尝试使用 weasyprint 生成可下载的 pdf。将来我希望能够将字节数组保存到数据库中,以便用户可以查看生成的报告,然后下载它们。但第一步是下载生成的 pdf 文件。当使用 weasyprint write_pdf() 方法并保存到光盘时,例如到test.pdf,打开文件时pdf是可以的。但是,当我尝试将 PDF 生成为变量并将其作为附件保存在 File- 或 HTTPresponse 中时,我只能在浏览器中获得带有如下字符的文本:

%PDF-1.7 %🖤 5 0 obj <> stream xڽXm  6  _ ? 9  IpZ  [(]h   n ܧ p   r d  ή   ױg yy     ( G 1       @     \ ? z     

我已经尝试了我能想到的一切,例如在 Http- 和 FileResponse 之间进行更改,将文件临时保存到光盘上,打开它然后将其传递给响应;使用缓冲区;等等..我也尝试过使用 Reportlab 库,但遇到了同样的问题。为了澄清,当我尝试使用 HttpResponse 时,我使用了以下代码:

response = HttpResponse(pdf_file, content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="test.pdf"'

我看到有人使用缓冲区解决了问题(使用Weasyprint创建文件响应),但它对我不起作用。下面的视图中对此代码进行了注释。我也遇到同样的问题

我发现其他人通过更改“交通警察”例程解决了这个问题,但我似乎找不到需要更改的代码(Django - 无法下载文件(显示为文本))。

此外,在 Chrome 中使用检查模式时,我看到响应包含必要的标头,例如内容处置和内容类型。

任何帮助或指导将不胜感激。如果您需要更多信息,请告诉我。

提前谢谢您!

编辑:该网站还使用 Alpine.js 和 HTMX。模板中没有由 write_pdf 方法呈现的 HTMX 或 Alpine.js 脚本。在我的基本站点中,我有一些 HTMX 属性:

<body x-data="{'isModalOpen': false}" hx-boost='True' hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>

查看文件:

from django.core.files import File
from django.db.models import Avg, Count, Case, When, IntegerField, DecimalField
from django.http import HttpResponse, FileResponse
from django.shortcuts import render
from django.template.loader import render_to_string
from django.views import View
from weasyprint import HTML
from salary.models import Salary

class CreateReportView(View):
    def get(self, request, *args, ** kwargs):

        ... # Omitted unrelevant code

        context = context={'results': results, 'results_per_gender': results_per_gender, 'results_per_region': results_per_region, 'results_titles': results_titles}
        rendered_html = render_to_string('report_template.html', context=context)

        # buffer = io.BytesIO()
        # pdf_file = HTML(string=rendered_html)
        # pdf_file.write_pdf(buffer)
        pdf_file = HTML(string=rendered_html).write_pdf()
        # buffer.seek(0)
        response = FileResponse(pdf_file, as_attachment=True, filename="test.pdf")
        return response
django django-views htmx
2个回答
1
投票
当不带参数调用时,

weasyprint.HTML.write_pdf()
返回一个
bytes
实例,但当使用参数调用时,它返回
None
。如果使用文件实例或文件的
str
路径作为
target
进行调用,则会将 PDF
bytes
数据写入
target
。您一直在服务器上所做的事情没有任何问题。

buffer = BytesIO()
HTML(string=html).write_pdf(buffer)
buffer.seek(0)
return FileResponse(buffer, as_attachment=True, filename="test.pdf")

问题完全出在客户端。当您将 HTMX 属性

hx-boost="true"
添加到任何 HTML 标签时,如下所示:

<div hx-boost="true">

HTMX 的作用是增强正常锚点和

Form
标签以使用AJAX。这有一个很好的效果,如果用户没有启用 javascript,网站将继续工作。

GET 请求会将请求 URL 推送到浏览器历史记录堆栈上(如果来自锚标记)。 响应正文将用于交换页面

innerHTML
标签的
body

如果响应正文是有效的 HTML,浏览器可以很好地呈现它。但既然不是,那就是问题所在。当使用 PDF 的

bytes
交换页面
innerHTML
标签的
body
时,浏览器无法渲染 PDF,因此得到的结果是:

%PDF-1.7 %🖤 5 0 obj <> stream xڽXm  6  _ ? 9  IpZ  [(]h   n ܧ p   r d  ή   ױg yy     ( G 1       @     \ ? z     

要完成响应并让浏览器自行处理下载,而不尝试将页面

innerHTML
标记的
body
与响应正文交换,请将
hx-swap="none"
属性添加到涉及发出请求的部分:

<div hx-boost="true" hx-swap="none">

0
投票

我没有在页面上提及我正在使用 HTMX。在我的基本页面中,我使用

hx-boost=true
(htmx) 作为我的 body 标记中的属性。删除该属性时,它似乎按预期工作。我现在意识到我应该提供这些额外的细节,但我认为它们在这种情况下并不重要。感谢您的帮助。

© www.soinside.com 2019 - 2024. All rights reserved.