Django视图调用ListView模板返回字符串供WeasyPrint生成PDF
核心问题答复
你完全可以通过配置ListView的context_object_name复用同一套模板,把渲染得到的HTML字符串直接传给WeasyPrint生成PDF,只要对齐视图和模板的上下文变量、替换成返回字符串的渲染方法即可,不需要额外复杂配置。
现有代码存在的几个会影响效果的问题
- ListView的自定义上下文属性名存在拼写错误:代码中写的
context_objecjt_name='cc'把object的最后一个t错写成了j,正确属性名是context_object_name,这个错误会导致自定义上下文名根本不生效。 - 视图里的渲染方法选错了:在
eprint函数里用的render()方法返回的是完整的HttpResponse响应对象,不是纯字符串形式的HTML内容,直接把这个对象传给WeasyPrint会解析失败,应该用render_to_string()直接拿到渲染后的字符串内容。 - 模板变量名和上下文不匹配:当前模板里循环遍历的是默认的
object_list,但你在PDF生成视图里传的上下文键是cc,两者对不上会导致循环拿不到任何数据,页面空白。 - 模板的HTML结构有缺陷:当前代码里连续写了两个
<form>开标签,没有闭合标签,会导致HTML结构错乱,WeasyPrint解析时可能出现样式偏移,顺手补上闭合标签即可。
调整方案和修正示例
- 先修正ListView的属性拼写,配置正确的
context_object_name,让模板可以通过cc变量取到数据集,不管是ListView的常规列表页访问,还是PDF生成的自定义视图调用,都能复用同一份模板逻辑。 - 在
eprint函数里引入render_to_string替代render(),直接获取字符串形式的渲染结果,传给WeasyPrint做解析。 - 调整模板里的循环遍历对象,把原来的
object_list替换成统一的cc变量,保证上下文和模板的对应关系一致,同时补全缺失的HTML闭合标签。
修正后的
eprint函数核心片段from django.template.loader import render_to_string from weasyprint import HTML def eprint(request): checked = request.GET.getlist('marked[]') res = [Concert.objects.get(pk=l) for l in checked] # 直接获取渲染后的HTML字符串,不生成完整响应对象 html_string = render_to_string('kammem/events.html', {'cc': res}) # 把字符串传给WeasyPrint生成PDF html = HTML(string=html_string) html.write_pdf(target='pdf/test.pdf') fs = FileSystemStorage('pdf') with fs.open('test.pdf') as pdf: response = HttpResponse(pdf, content_type='application/pdf') response['Content-Disposition'] = 'attachment; filename="test.pdf"' return response
修正后的ListView代码
class Events(ListView): # 修正原代码的拼写错误 context_object_name = 'cc' model = Concert template_name = 'kammem/events.html'
修正后的模板核心逻辑
{# 把遍历对象改成和上下文统一的cc变量 #} {% for l in cc %} <tr> <td> <form> <label><input type="checkbox" id={{l.pk}} name="checkb"></label> </form> </td> <td><a href="eupdate/{{l.pk}}"><i class="bi bi-pencil-square"></i></a></td> <td><a href="edelete/{{l.pk}}"><i class="bi bi-trash"></i></a></td> <td>{{l.pk}}</td> <td>{{l.cname}}</td> <td><a href="detail/{{l.venue.pk}}">{{l.venue}}</a></td> <td>{{l.date}}</td> <td><a href="detail/{{l.organizer.pk}}">{{l.organizer}}</a></td> <td>{{l.antmus}}</td> <td>{{l.män1}}/{{l.kvinnor1}}</td> <td>{{l.publik}}</td> <td>{{l.män2}}/{{l.kvinnor2}}</td> </tr> {% endfor %} </tbody>
内容的提问来源于stack exchange,提问作者Jonas Fredriksson
相关产品推荐
相关产品推荐

