首页 > 解决方案 > weasyprint 没有正确渲染 bootstrap4 css

问题描述

我试图通过首先将其设计为 HTML 并将其提供给 weasyprint 以生成 pdf 来生成发票。我正在使用带有 bootstrap 4.3.1 和 weasyprint 50 的 Django 2.2.5 版本。该函数invoice_generator(request)使用 和 调用 generate_invoicerequest函数。usernametemplate_name

视图.py:

from invoice_generator import generate_invoice

def invoice_generator(request, username):
    ret_val = generate_invoice(request, username, template_name="ui/invoice.html")
    return ret_val

发票生成器.py:

from django.shortcuts import render
from commons.models import SMSUser, SMSMessages, Invoice
from commons.serializers import InvoiceSerialzer

from django.template.loader import get_template
from django.conf import settings
from django.http import HttpResponse

from weasyprint import HTML, CSS
import tempfile

from datetime import datetime, date

def generate_invoice(request, username, template_name):
    user_to_invoice = SMSUser.objects.get(username=username)
    user_invoice = Invoice(invoice_to=user_to_invoice)

    company_to_invoice = user_to_invoice.company_name
    company_tin = user_to_invoice.company_tin
    account = user_to_invoice.pk
    user_email = user_to_invoice.email
    all_users_in_company = SMSUser.objects.filter(company_name=company_to_invoice)
    user_invoice.save()
    invoice_number = user_invoice.pk
    paid_status = user_invoice.payment_status

    all_sms_sent_by_users = {}

    for user in all_users_in_company:
        # TODO you can run the code at the begining of each month by doing:
        # TODO x = date.today() then x = x.replace(day=1) 
        total_sent_by_single_user = SMSMessages.objects.filter(
            sending_user=user,
            delivery_status="True",
            sent_date__year=datetime.now().year,
            sent_date__month = 10
            # sent_date__month = datetime.now().month - 2
            )
        all_sms_sent_by_users = {
            "all_sms_sent": [
                {
                "user": user,
                "total_sent_single_user": total_sent_by_single_user.count()
                }
            ]
        }
    total_amount_sent = SMSMessages.objects.filter(
        sent_date__year = datetime.now().year,
        sent_date__month = 10,
        # sent_date__month = datetime.now().month - 1,
        sending_user__company_name=company_to_invoice
    )

    # TODO feed the below object to a pdf renderer and return that pdf rendered object
    context_object =  {
        "username": user_to_invoice,
        "company_name": company_to_invoice,
        "account": account,
        "invoice_number": invoice_number,
        "tin": company_tin,
        "email": user_email,
        "bill_month": datetime.now().month - 1,
        "all_sms_sent": all_sms_sent_by_users,
        "total_amount_sent": total_amount_sent.count(),
        "vat": total_amount_sent.count() * 0.70 * 0.15,
        "total_price": total_amount_sent.count() * 0.70 * 1.15, 
        "payment_status": paid_status
    }

    rendered_html = get_template(template_name).render(
       context_object,
        request
    ).encode(encoding='UTF-8')

    pdf_file = HTML(string=rendered_html, base_url=request.build_absolute_uri())
    pdf_file.render()
    pdf_container = pdf_file.write_pdf(
        stylesheets=[
            CSS(
                'ui' + settings.STATIC_URL + 'ui/css/bootstrap.min.css'
            )
        ]
    )
    response = HttpResponse(content_type='application/pdf;')
    response['Content-Disposition'] = 'filename=Invoice ' + company_to_invoice + str(datetime.now().month) + '.pdf'
    response['Content-Transfer-Encoding'] = 'UTF-8'
    with tempfile.NamedTemporaryFile(delete=True) as pdf_writer:
        pdf_writer.write(pdf_container)
        pdf_writer.flush()
        pdf_writer = open(pdf_writer.name, 'rb')
        response.write(pdf_writer.read())
    return response

这是ui/invoice.html

<!DOCTYPE html>
<html lang="en">
<head>
    {% load static %}
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
    <link rel="shortcut icon" type="image/png" href="{% static 'ui/images/favicon.ico' %}">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <!-- bootstrap4 css -->
    <link href="{% static 'ui/css/bootstrap.min.css' %}" rel="stylesheet" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <title>sms.et | Invoice</title>
</head>
<body class="text-center d-print-block" style="background-color: #f5f5f5;">
    <div class="container-fluid align-items-center align-middle">
        <header>
            <div class="row">
                <div class="col-md-12 bg-primary">
                    <h1 class="font-weight-bold self-center h1 text-white">Service Invoice</h1>
                </div>
            </div>
            <br>
            <div class="row">
                <div class="col-md-6">
                    <h4 class="font-weight-light self-center h4"><p>Customer Name: <span class="font-weight-lighter"> {{ username.company_name }}</span></p></h4>
                    <h4 class="font-weight-light self-center h4"><p>Account: <span class="font-weight-lighter"> {{ account }}</span></p></h4>
                    <h4 class="font-weight-light self-center h4"><p>T.I.N: <span class="font-weight-lighter"> {{ tin }}</span></p></h4>
                </div>
                <div class="col-md-6">
                    <h4 class="font-weight-light self-center h4"><p>Invoice number: <span class="font-weight-lighter"> {{ invoice_number }}</span></p></h4>
                    <h4 class="font-weight-light self-center h4"><p>Email: <span class="font-weight-lighter"> {{ email }}</span></p></h4>
                    <h4 class="font-weight-light self-center h4"><p>Bill Month: <span class="font-weight-lighter"> {{ bill_month }}</span></p></h4>
                    <h4 class="font-weight-light self-center h4"><p>Due date: <span class="font-weight-lighter"> 5 days from this invoice</span></p></h4>
                </div>
            </div>
        </header>
    </div>
    <hr class="bg-primary">
    <h6 class="font-weight-lighter self-center h6"><p>Paid status: {{payment_status}}</p></h6>
    <hr class="bg-primary">

    <div class="container-fluid">
        <div class="row">
            <div class="col-md-6">
                <label class="font-weight-light self-center h2">All users that sent sms:</label>
                <div class="row">
                    <div class="col-md-4">
                        <!-- dict object all _sms_sent is garnered from the views and parsed accordingly as key & value of all_sms_sent.items -->
                        {% for key, value in all_sms_sent.items %}
                        <h4 class="font-weight-lighter h4">username</h4>
                        {% for val in value %}
                        <p>{{ val.user }}</p>
                    </div>
                    <div class="col-md-4">
                        <h4 class="font-weight-lighter h4">Company</h4>
                        <p>{{ val.user.company_name }}</p>
                    </div>
                    <div class="col-md-4">
                        <h4 class="font-weight-lighter h4">Total sent</h4>
                         <p>{{ val.total_sent_single_user }}</p>
                         {% endfor %}
                         {% endfor %}
                    </div>
                </div>
            </div>
            <div class="col-md-6">
                <div class="row">
                    <div class="col-md-6">
                        <h4 class="font-weight-light self-center h4">Total sms sent in the month:</h4>
                    </div>
                    <div class="col-md-6">
                        <p>{{ total_amount_sent }}</p>
                    </div>
                </div>
                <br>
                <div class="row">
                    <div class="col-md-6">
                        <h4 class="font-weight-light self-center h4">Price per text:</h4>
                    </div>
                    <div class="col-md-6">
                        <p>0.70 Birr</p>
                    </div>
                </div>
                <br>
                <div class="row">
                    <div class="col-md-6">
                        <h4 class="font-weight-light self-center h4">V.A.T:</h4>
                    </div>
                    <div class="col-md-6">
                        <p>{{ vat }} Birr</p>
                    </div>
                    <br>
                </div>
                <br>
                <div class="row">
                    <div class="col-md-6">
                        <h4 class="font-weight-light self-center h4">Total:</h4>
                    </div>
                    <div class="col-md-6">
                        <p>{{ total_price }} Birr</p>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <br>
    <br>
    <div class="container-fluid align-items-center align-middle bg-primary">
        <footer>
            <div class="row text-white">
                <div class="col-md-4">
                    <h4 class="font-weight-light self-center h4"><p>Address</p></h4>
                    <p class="quote font-weight-light center">Ethiopia, Addis Ababa, Kirkos sub-city, woreda 02,  House No. 700.</p>
                </div>
                <div class="col-md-4">
                    <img src="{% static 'ui/images/logo.jpg' %}" width="50" height="40" class="d-inline-block align-top navbar-brand" alt="">
                    <br>
                    <a href="www.sms.et" class="text-white blockquote">www.sms.et</a>
                </div>
                <div class="col-md-4">
                    <p class="quote font-weight-light center">Outstanding bill must be settled 5 days after issuance of this service invoice.</p>
                    <p class="quote font-weight-light center">Any questions can be forwared to us via our phone number: +251977207777</p>
                </div>
            </div>
        </footer>
    </div>
</body>
</html>

问题是 weasyprint 没有按预期呈现引导程序 4 css,即如上所述。这是一个问题Bootstrap CSS is not applied in weasyprint 这与我的问题很接近,但所描述的解决方案没有任何区别。澄清一下,这就是它应该看起来的样子(html 版本) 它应该是什么样子:. 但它最终看起来像这样: 两页的第一页 还有这个: 两页的第二页 有人可以帮忙吗?

编辑以包含项目和应用程序的 urls.py

这是项目中的 urls.py:

urlpatterns = [
    # for the ui app
    path('ui/', include('ui.urls')),
]

这是 ui 应用程序的 urls.py:

from django.urls import path
from . import views

app_name = "ui"

urlpatterns = [
    path('homepage/', views.homepage, name="homepage"),
    path('login/', views.login_request, name="login"),
    path('dashboard/<username>/', views.dashboard, name="dashboard"),
    path('logout/', views.logout_request, name="logout"),
    path('register/', views.register_request, name="register"),
    path('ajax/dashboard_update/', views.ajax_dashboard_update, name="ajax_dashboard_update"),
    path('<username>/invoice/', views.invoice_generator, name="invoice_generator"),
]

标签: cssdjangopython-3.xbootstrap-4weasyprint

解决方案


推荐阅读