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>
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.