Search code examples
djangodjango-viewsxhtml2pdf

Converting relative url path to absolute url for xhtml2pdf


I am very inexperienced in this so I have problem understanding documentation provided for xhtml2pdf since it is very vague in details. Please tell me what I am doing wrong.

According to documentation to convert relative url path to absolute I need to use provided function:

def link_callback(uri, rel):
    """
    Convert HTML URIs to absolute system paths so xhtml2pdf can access those
    resources
    """
    # use short variable names
    sUrl = settings.STATIC_URL      # Typically /static/
    sRoot = settings.STATIC_ROOT    # Typically /home/userX/project_static/
    mUrl = settings.MEDIA_URL       # Typically /static/media/
    mRoot = settings.MEDIA_ROOT     # Typically /home/userX/project_static/media/

    # convert URIs to absolute system paths
    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 uri  # handle absolute uri (ie: http://some.tld/foo.png)

    # 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

I added exact same function to my views.py and using this function for generating pdf (also in views.py, almost directly taken form docs):

def PGP_result(request):

    data = request.session['form_data']

    lietuvosPgp = data['LtPGP']
    valstybe = data['pVal']
    kastai = data['iKastai']
    rezultatas = data['result']  
    today = timezone.now()

    params = {
            'LtPgp': lietuvosPgp,
            'Valstybe': valstybe,
            'Kastai': kastai,
            'Rezultatas': rezultatas,
            'today': today,
        }

    template_path = 'PGP_results_pdf.html'

    response = HttpResponse(content_type='application/pdf')
    response['Content-Disposition'] = 'attachment; filename="test.pdf"'

    template = get_template(template_path)
    html = template.render(params)

    pisaStatus = pisa.CreatePDF(
        html, dest=response, link_callback=link_callback
        )
    if pisaStatus.err:
        return HttpResponse('Ups kažkas nepavyko <pre>' + html + '</pre>')
    return response

Pdf is generated, but font file residing in static/fonts folder is not used. I cannot figure out how to correctly write relative url path so it would be converted to absolute one. I guess solution should be very simple, but my lack of experience prevents me from finding it (I tired various ways of writing it, but none of them worked) .

My (current) template code (do not know how to fix src: url(sUrl/fonts/Arial.ttf) part):

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>Test</title>
   <style type="text/css">
         @font-face {
            font-family: "Arial"; src: url(sUrl/fonts/Arial.ttf);
        }
        .container {
            font-family: "Arial"
        }
    </style>
</head>
<body>
<div class="container">
    <div class="card">
        <div class="card-header">
            <h3>Skaičiuota - {{ today | date:"d/m/Y" }}</h3>
        </div>  
        <div class="list-group">
            <p>{{ LtPgp }}</p>
            <p>{{ Valstybe }}</p>
            <p>{{ Kastai }}</p>
            <p>{{ Rezultatas }}</p>
        </div>
    </div>
</div>
</body>
</html>

Solution

  • After reading bunch of more or less similar questions, I stumbled on comment recommending to run py manage.py collectstatic command first. After reading this and analyzing `link_callback function more I found solution:

    In template should be: font-family: "Arial"; src: "static/fonts/Arial.ttf";

    In my conclusion link_callback function checks for the link first part and if it finds that link starts with static it replaces it with directory to STATIC_ROOT (absolute path). Since I was working on development server with Debug=True I did not needed to collectstatic for everything else, so while everything worked, link_callback function directed to non existing (yet) directory. After collecting all the statics and fixing source link I got it working.

    P.S. I am not professional and have no programming background, so please fix my assumptions if they are wrong (I realy want to learn and know more). But even if assumptions are wrong code now works fine.