xhtml2pdf-使用django forloop标记显示表行的问题

问题描述

我要执行的操作是创建带有多个表行的发票pdf文件。表行将在Django中使用for循环创建。问题是for循环标记中的数据在pdf文件中不可见。 您可以查看以下屏幕截图。 Django正确渲染了invoice.html模板,因此代码有效,但是pdf文件包含空框架,没有任何表行。要从html渲染pdf,我使用的是xhtml2pdf。

how django render the invoice.html template

how pdf file looks like

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 %}

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...