问题描述
我要执行的操作是创建带有多个表行的发票pdf文件。表行将在Django中使用for循环创建。问题是for循环标记中的数据在pdf文件中不可见。 您可以查看以下屏幕截图。 Django正确渲染了invoice.html模板,因此代码有效,但是pdf文件包含空框架,没有任何表行。要从html渲染pdf,我使用的是xhtml2pdf。
how django render the invoice.html template
invoice.html
<html>
<head>
{% load static %}
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta charset="UTF-8">
<style>
@font-face {
font-family: Roboto;
src: url('{% static 'fonts/Roboto-Regular.ttf' %}');
}
@font-face {
font-family: Roboto-bold;
src: url('{% static 'fonts/Roboto-Bold.ttf' %}');
font-weight: bold;
}
@page {
size: a4 portrait;
@frame header_frame { /* Static Frame */
-pdf-frame-content: frame_header_left;
left: 50pt; width: 245pt; top: 30pt; height: 150pt;
}
@frame header_frame { /* Static Frame */
-pdf-frame-content: frame_header_right;
left: 300pt; width: 245pt; top: 50pt; height: 150pt;
}
@frame content_frame { /* Content Frame */
-pdf-frame-content: frame_invoice_number;
left: 50pt; width: 512pt; top: 170pt; height: 30pt;
}
@frame col1 {
-pdf-frame-content: frame_col1;
left: 50pt; width: 245pt; top: 220pt; height: 130pt;
}
@frame col2 {
-pdf-frame-content: frame_col2;
left: 300pt; width: 245pt; top: 220pt; height: 130pt;
}
@frame frame_services {
-pdf-frame-content: frame_services;
left: 50pt; width: 512pt; top: 380pt; height: 250pt;
-pdf-frame-border: 1;
}
@frame content_frame {
-pdf-frame-content: frame_summary;
left: 465pt; width: 100pt; top: 590pt; height: 50pt;
}
@frame content_frame {
-pdf-frame-content: frame_vat;
left: 50pt; width: 512pt; top: 590pt; height: 150pt;
}
@frame content_frame {
-pdf-frame-content: frame_signatures_left;
left: 50pt; width: 140pt; top: 725pt; height: 70pt;
}
@frame content_frame {
-pdf-frame-content: frame_signatures_right;
left: 400pt; width: 140pt; top: 725pt; height: 70pt;
left: 400pt; width: 140pt; top: 725pt; height: 70pt;
}
@frame content_frame {
-pdf-frame-content: footer_content;
left: 50pt; width: 512pt; top: 775pt; height: 50pt;
}
}
body {
background-color: white;
font-family: "Roboto",sans-serif;
}
.right{
font-size: 10px;
text-align: right;
}
.left{
text-align: left;
}
.invoice-number {
font-size: 18px;
font-family: "Roboto-bold",sans-serif;
}
.col-titles {
font-size: 16px;
text-decoration: underline;
font-family: "Roboto-bold",sans-serif;
}
.footer {
font-size: 8px;
text-align: center;
}
p{
font-size: 10px;
line-height: 0;
}
table {
border-bottom: 1px solid #ddd;
text-align: center;
}
td,td {
border-bottom: 1px solid #ddd;
vertical-align: middle;
}
.summary{
border-bottom: 1px solid #ddd;
}
.signatures {
border-top: 1px solid black;
font-size: 8px;
text-align: center;
}
th {
height: 36px;
}
td {
height: 25px;
}
</style>
</head>
<body>
<div>
<div>
<div id="frame_header_left" class="left">
<img src="{% static 'invoices/logo.png' %}" alt="logo" width="150" height="112">
</div>
<div id="frame_header_right" class="right">
<p>Miejsce wystawienia: Żabno</p>
<p>Data badania: {{ invoice.data_badania }}</p>
<p>Data wystawienia: {{ invoice.data_wystawienia_faktury }}</p>
</div>
</div>
<div id="frame_invoice_number">
<div class="invoice-number">
<h2>Faktura nr: {{ invoice.numer }}</h2>
</div>
</div>
<div id="frame_col1">
<p class="col-titles">Sprzedawca</p>
<div>
<p>MEDIKAP</p>
<p>ul. Plac Grunwaldzki 15B,33-240 Żabno</p>
<p>NIP: 999999999</p>
<p>REGON: 9999999</p>
<p>Bank: ING Bank Śląski</p>
<p>Nr konta: 12 1234 1234 1243 1243 214 1244</p>
</div>
</div>
<div id="frame_col2">
<p class="col-titles">Nabywca</p>
<div>
<p> {{ invoice.firma}} </p>
<p> ul. {{ invoice.firma.ulica }} </p>
<p> {{ invoice.firma.kod_pocztowy }} {{ invoice.firma.miasto}}</p>
<p> NIP: {{ invoice.firma.nip }}</p>
<p> REGON: {{ invoice.firma.regon }}</p>
<p> forma płatności: {{ invoice.get_forma_platnosci_display}}</p>
</div>
</div>
<div id="frame_services">
<table>
<tr>
<th style="width: 50px;"> # </th>
<th style="width: 600px;"> Nazwa usługi</th>
<th style="width: 100px;"> Ilość</th>
<th style="width: 100px;"> Rabat[%]</th>
<th style="width: 100px;"> Cena usługi</th>
<th style="width: 100px;"> Wartość</th>
<th style="width: 100px;"> Wartość z rabatem:</th>
</tr>
{% for service in services_items %}
<tr>
<td> test </td>
<td> test </td>
</tr>
{% endfor %}
</table>
</div>
<div id="frame_summary" class="summary">
<p> : {{ service.get_total_value }} PLN</p>
<p> Wartość z uwzględnieniem {{ invoice.rabat}}% rabatu: {{ discounted_value|floatformat:"-2" }} PLN</p>
</div>
<div id="frame_vat">
<p> Podstawa zwolnienia z VAT: </p>
<p> Zwolnienie ze względu na zakres wykonywanych czynności (art. 43 ust.1) pkt 19 Ustawy o VAT</p>
</div>
<div id="frame_signatures_left">
<p class="signatures"> podpis osoby upoważnionej do odbioru faktury</p>
</div>
<div id="frame_signatures_right">
<p class="signatures"> podpis osoby upoważnionej do wystawienia faktury</p>
</div>
<div id="footer_content" >
<p class="footer">MEDIKAP Maria K.</p>
<p class="footer">Plac Grunwaldzki 15B,33-240 Żabno</p>
<p class="footer">e-mail: gabinet.medikap@gmail.com tel: 539 993 332</p>
<p class="footer">NIP: 9930212793 REGON: 852441210</p>
</div>
</div>
</body>
</html>
views.py/DetailsInvoice
class DetailsInvoice(generic.View):
template_name = 'invoices/invoice_detail.html'
form_class = DetailInvoiceForm
success_url = reverse_lazy("invoices:list")
def get(self,request,invoice_id):
current_invoice = get_object_or_404(Invoice,id=invoice_id)
form = self.form_class(instance=current_invoice)
request.session['invoice_id'] = current_invoice.id
services = Service.objects.all()
all_service_items = ServiceItem.objects.all().filter(faktura = current_invoice).order_by('usluga')
context = {
'invoice': current_invoice,'form' : form,'services' : services,'services_items' : all_service_items,}
return render(request,self.template_name,context)
def post(self,invoice_id):
current_invoice = get_object_or_404(Invoice,id=invoice_id)
form = self.form_class(request.POST,instance=current_invoice)
all_service_items = ServiceItem.objects.all().filter(faktura=current_invoice)
context = {
'invoice' : current_invoice,}
pdf = render_to_pdf('invoices/invoice.html',context)
services_assigned_to_invoice = current_invoice.uslugi.all()
if 'update-data' in request.POST and form.is_valid():
for service in all_service_items:
service_item = get_object_or_404(ServiceItem,id=service.id)
quantity_input = request.POST.get('quantity-' + str(service.id))
discount_input = request.POST.get('discount-' + str(service.id))
service_item.ilosc = int(quantity_input)
service_item.rabat = int(discount_input)
service_item.save()
form.save()
for service_item in all_service_items:
if service_item.usluga not in services_assigned_to_invoice:
service_item.delete()
for single_service in services_assigned_to_invoice:
new_service_item,created = ServiceItem.objects.get_or_create(usluga=single_service,faktura=current_invoice)
messages.success(request,'Pomyślnie zaktualizowane dane')
return HttpResponseRedirect(self.request.META.get('HTTP_REFERER'))
if 'view-pdf' in request.POST:
return HttpResponse(pdf,content_type='application/pdf')
if 'download-pdf' in request.POST:
response = HttpResponse(pdf,content_type='application/pdf')
filename = f"Faktura {current_invoice.numer}.pdf"
content = "attachment; filename={}".format(filename)
response['Content-Disposition'] = content
return response
else:
return redirect('invoices:list')
渲染功能
def render_to_pdf(template_src,context_dict={}):
template = get_template(template_src)
html = template.render(context_dict)
result = BytesIO()
pdf = pisa.pisaDocument(BytesIO(html.encode("utf-8")),result,link_callback=link_callback)
if not pdf.err:
return HttpResponse(result.getvalue(),content_type='application/pdf')
return None
解决方法
您没有将与传递给HTML模板相同的上下文变量传递给PDF。您正在传递到HTML模板:
context = {
'invoice': current_invoice,'form' : form,'services' : services,'services_items' : all_service_items,}
在传递PDF时,您只是通过:
context = {
'invoice' : current_invoice,}
services_items
是您的PDF模板似乎丢失的模板。因此,由于for service in services_items
在您的PDF模板中是一个空/不存在的列表,因此它不会呈现任何行。将来,您可以通过在{% empty %}
循环中添加for
部分来进行检查:
{% for service in services_items %}
<tr>
<td> test </td>
<td> test </td>
</tr>
{% empty %}
No items!
{% endfor %}