django /媒体URI中XHTML2PDF编码的UTF-8必须以 / static / or / /媒体 / / / / / /媒体 /的

发布于 2025-01-19 22:41:29 字数 6454 浏览 0 评论 0原文

我正在使用 xhtml2pdf 包从 django 应用程序中的 html 模板生成 pdf 文件。 pdf 文件生成正确(没有错误),但是,我遇到了 UTF-8 编码的问题。我生成的 pdf 文件显示黑色方块,而不是特殊字符(PL 语言)。我已经浏览了几乎所有在线可用的解决方案,但没有一个有帮助。当我使用 ReportLab 并在没有模板的情况下生成 pdf 时,一切似乎都很好。 我是否在景观方面错过了一些东西?

要更新,我相信我遇到的问题实际上是在检索字体。 我添加了回调链接,并尝试在模板中使用 {% static %} 引用。但这会引发错误媒体 URI 必须以 /static/ 或 /media/ 开头

我的 html 模板

{% load static %}

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    <title>PDF {{obj.orderNumber}}</title>
    <style>

        

        @font-face {
            font-family: "Roboto-Black";
            src: url({% static "fonts/Roboto.ttf" %});
        }
        @font-face {
            font-family: "Roboto-Regular";
            src: url({% static "Roboto-Regular.ttf" %});
        }
        @font-face {
            font-family: "Roboto-Bold";
            src: url({% static "Roboto-Bold.ttf" %});
            font-weight: bold;
        }

           
            body, html  {
            font-family: Roboto;
    
           }

        
        table { -pdf-keep-with-next: true; }
        p { margin: 0; -pdf-keep-with-next: true; }
        p.separator { -pdf-keep-with-next: false; font-size: 6pt; }
 
        .bander{
            color:brown; 
            font-size:13pt;
        }
    </style>

</head>

<body>
    <img src="media/logo.jpg" style="height:60px;">
    <h2> PLAN ROZKROJU ZLECENIA: </h2>
    <h1 style="color:#997207;">{{obj.orderNumber}} {{obj.orderName}}</h3>
        <h2> Naklad: {{obj.orderQuantity}} szt </h2>
        <h4> Data utworzenia wydruku: {{obj3}} </h4>
        
        <div>
            <table class="table table-bordered" style="text-align: center; padding: 5px;" border="0.2">
                <thead class="table-active">
                    <tr>
                        <th scope="col">Nazwa materialu</th>
                        <th scope="col">Ilosc</th>
                        <th scope="col">Nazwa czesci</th>
                        <th scope="col">Wymiar (mm)</th>
                        <th scope="col">Wymiar 2 (mm)</th>
                        
                    </tr>
                </thead>

                <tbody>
                    {% for item in obj2 %}
                    <tr>
                        <td>{{ item.itemMaterial }}</td>
                        <td>{{ item.itemQuantity }} szt</td>
                        <td>{{ item.itemName }}</td>
                        {% if item.itemBander == 'OKLEJANIE 1 STR' %}
                            <td class="text-center"><b class="bander">*</b> {{ item.itemDimmension1 }}</td>
                        {% elif item.itemBander == 'OKLEJANIE 2 STR' %}
                            <td class="text-center"><b class="bander">*</b> {{ item.itemDimmension1 }} <b class="bander">*</b></td>
                        {% else %}
                            <td class="text-center">{{ item.itemDimmension1 }}</td>
                        {% endif %}

                         {% if item.itemBander2 == 'OKLEJANIE 1 STR' %}
                            <td class="text-center"><b class="bander">*</b> {{ item.itemDimmension2 }}</td>
                        {% elif item.itemBander2 == 'OKLEJANIE 2 STR' %}
                            <td class="text-center"><b class="bander">*</b> {{ item.itemDimmension2 }} <b class="bander">*</b></td>
                        {% else %}
                            <td class="text-center">{{ item.itemDimmension2 }}</td>
                        {% endif %}

                    </tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
        <p></p>
        <h6><i> LEGENDA:<b class="bander">*</b> wymiar - oklejanie 1-str // <b class="bander">*</b> wymiar <b class="bander">*</b> - oklejanie 2 str</i></h6>
            
</body>

</html>

我的views.py

def link_callback(uri, rel):
    """
    Convert HTML URIs to absolute system paths so xhtml2pdf can access those
    resources
    """

    sUrl = settings.STATIC_URL            # Typically /static/
    sRoot = settings.STATIC_ROOT          # Typically /home/userX/project_static/
    mUrl = settings.MEDIA_URL             # Typically /media/
    mRoot = settings.MEDIA_ROOT           # Typically /home/userX/project_static/media/
    bRoot = settings.BASE_DIR             # Project's base directory

    if uri.startswith(mUrl):
        path = os.path.join(mRoot, uri.replace(mUrl, ""))
    elif uri.startswith(sUrl):
        path = os.path.join(sRoot, uri.replace(sUrl, ""))
    else:
        return os.path.join(bRoot, '../', uri)

    # make sure that file exists
    if not os.path.isfile(path):
        raise Exception(
            'media URI must start with %s or %s' % (sUrl, mUrl)
        )
    return path
# PDF VIEWS#
@login_required
@admin_or_manager_required
def render_pdf_view(request, pk):
    template_path = "orders/pdf.html"
    obj = get_object_or_404(Order, pk=pk)
    obj2 = Item.objects.filter(itemOrder=obj)
    obj3 = datetime.now()

    context = {"obj": obj, "obj2": obj2, "obj3": obj3}

    response = HttpResponse(content_type="application/pdf")
    response["Content-Disposition"] = 'filename="file.pdf"'
    template = get_template(template_path)
    html = template.render(context)

    
    pisa_status = pisa.CreatePDF(html.encode("UTF-8"), response , encoding='UTF-8', link_callback=link_callback)

    if pisa_status.err:
        return HttpResponse("We had some errors <pre>" + html + "</pre>")
    return response

我的settings.py

STATIC_URL = "/static/"
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, ""),
    os.path.join(BASE_DIR, "static")
]
STATIC_ROOT = "static_root"

MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")

I am using xhtml2pdf package to generate a pdf file from an html template in my django application. The pdf file generates correctly (no errors), however, I have encountered a problem with UTF-8 encoding. My generated pdf file, instead of special charactes (PL language), shows black squares. I have gone through almost all solutions available online, but none of them helped. When I am using ReportLab and generate pdf without a template, all seems to be okay.
Am I missing something perhaps on the views side?

To update, I believe the problem I have is really in retrieving the font.
I have added the callback_link, and tried to used {% static %} reference in my template. But this throws an error media URI must start with /static/ or /media/

My html template

{% load static %}

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    <title>PDF {{obj.orderNumber}}</title>
    <style>

        

        @font-face {
            font-family: "Roboto-Black";
            src: url({% static "fonts/Roboto.ttf" %});
        }
        @font-face {
            font-family: "Roboto-Regular";
            src: url({% static "Roboto-Regular.ttf" %});
        }
        @font-face {
            font-family: "Roboto-Bold";
            src: url({% static "Roboto-Bold.ttf" %});
            font-weight: bold;
        }

           
            body, html  {
            font-family: Roboto;
    
           }

        
        table { -pdf-keep-with-next: true; }
        p { margin: 0; -pdf-keep-with-next: true; }
        p.separator { -pdf-keep-with-next: false; font-size: 6pt; }
 
        .bander{
            color:brown; 
            font-size:13pt;
        }
    </style>

</head>

<body>
    <img src="media/logo.jpg" style="height:60px;">
    <h2> PLAN ROZKROJU ZLECENIA: </h2>
    <h1 style="color:#997207;">{{obj.orderNumber}} {{obj.orderName}}</h3>
        <h2> Naklad: {{obj.orderQuantity}} szt </h2>
        <h4> Data utworzenia wydruku: {{obj3}} </h4>
        
        <div>
            <table class="table table-bordered" style="text-align: center; padding: 5px;" border="0.2">
                <thead class="table-active">
                    <tr>
                        <th scope="col">Nazwa materialu</th>
                        <th scope="col">Ilosc</th>
                        <th scope="col">Nazwa czesci</th>
                        <th scope="col">Wymiar (mm)</th>
                        <th scope="col">Wymiar 2 (mm)</th>
                        
                    </tr>
                </thead>

                <tbody>
                    {% for item in obj2 %}
                    <tr>
                        <td>{{ item.itemMaterial }}</td>
                        <td>{{ item.itemQuantity }} szt</td>
                        <td>{{ item.itemName }}</td>
                        {% if item.itemBander == 'OKLEJANIE 1 STR' %}
                            <td class="text-center"><b class="bander">*</b> {{ item.itemDimmension1 }}</td>
                        {% elif item.itemBander == 'OKLEJANIE 2 STR' %}
                            <td class="text-center"><b class="bander">*</b> {{ item.itemDimmension1 }} <b class="bander">*</b></td>
                        {% else %}
                            <td class="text-center">{{ item.itemDimmension1 }}</td>
                        {% endif %}

                         {% if item.itemBander2 == 'OKLEJANIE 1 STR' %}
                            <td class="text-center"><b class="bander">*</b> {{ item.itemDimmension2 }}</td>
                        {% elif item.itemBander2 == 'OKLEJANIE 2 STR' %}
                            <td class="text-center"><b class="bander">*</b> {{ item.itemDimmension2 }} <b class="bander">*</b></td>
                        {% else %}
                            <td class="text-center">{{ item.itemDimmension2 }}</td>
                        {% endif %}

                    </tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
        <p></p>
        <h6><i> LEGENDA:<b class="bander">*</b> wymiar - oklejanie 1-str // <b class="bander">*</b> wymiar <b class="bander">*</b> - oklejanie 2 str</i></h6>
            
</body>

</html>

My views.py

def link_callback(uri, rel):
    """
    Convert HTML URIs to absolute system paths so xhtml2pdf can access those
    resources
    """

    sUrl = settings.STATIC_URL            # Typically /static/
    sRoot = settings.STATIC_ROOT          # Typically /home/userX/project_static/
    mUrl = settings.MEDIA_URL             # Typically /media/
    mRoot = settings.MEDIA_ROOT           # Typically /home/userX/project_static/media/
    bRoot = settings.BASE_DIR             # Project's base directory

    if uri.startswith(mUrl):
        path = os.path.join(mRoot, uri.replace(mUrl, ""))
    elif uri.startswith(sUrl):
        path = os.path.join(sRoot, uri.replace(sUrl, ""))
    else:
        return os.path.join(bRoot, '../', uri)

    # make sure that file exists
    if not os.path.isfile(path):
        raise Exception(
            'media URI must start with %s or %s' % (sUrl, mUrl)
        )
    return path
# PDF VIEWS#
@login_required
@admin_or_manager_required
def render_pdf_view(request, pk):
    template_path = "orders/pdf.html"
    obj = get_object_or_404(Order, pk=pk)
    obj2 = Item.objects.filter(itemOrder=obj)
    obj3 = datetime.now()

    context = {"obj": obj, "obj2": obj2, "obj3": obj3}

    response = HttpResponse(content_type="application/pdf")
    response["Content-Disposition"] = 'filename="file.pdf"'
    template = get_template(template_path)
    html = template.render(context)

    
    pisa_status = pisa.CreatePDF(html.encode("UTF-8"), response , encoding='UTF-8', link_callback=link_callback)

    if pisa_status.err:
        return HttpResponse("We had some errors <pre>" + html + "</pre>")
    return response

My settings.py

STATIC_URL = "/static/"
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, ""),
    os.path.join(BASE_DIR, "static")
]
STATIC_ROOT = "static_root"

MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文