Why in this PDF file generated in this example not able to add watermark Pyhton3 - django

Why in this PDF file generated in this example not able to add watermark . How can I fix it? (There is no error, just does not able to display "WATERMARK".).
template_name = assign_custom_template(template_name)
template_path = template_name
e_library_list = Elibrary.objects.get(pk=e_library_id,)
retrun_questionlist = {}
for e_library_question_list in e_library_list.products.all():
questionlist = MCQAnswerFiled.objects.filter(group__pk=e_library_question_list.id)
retrun_questionlist[e_library_question_list.id] = questionlist
context = {'e_library_list': e_library_list,'retrun_questionlist':retrun_questionlist}
# Create a Django response object, and specify content_type as pdf
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="report.pdf"'
# find the template and render it.
template = get_template(template_path)
html = render_to_string(template_path, context)
response = BytesIO()
file = open('sheetstudentcopy.pdf', "w+b")
pdf = pisa.pisaDocument(BytesIO(html.encode("UTF-8")), file,link_callback=link_callback)
file.seek(0)
pdf = file.read()
file.close()
return HttpResponse(pdf, 'application/pdf')

You should include the watermark image directly into your CSS template, as described in the documentation:
https://xhtml2pdf.readthedocs.io/en/latest/reference.html#page-background-image
For example:
#page {
background-image: url('/path/to/pdf-background.jpg');
}

Related

Generate multiple PDFs and zip them for download, all in a single view

I am using xhtml2pdf to generate PDFs in my Django View. The idea is to loop over all the instances that are there in the query, then for each instance create a PDF, then add all the generated PDFs to one zip File for download. The xtml2pdf logic is working okay but the looping logic is what gives me headache.
So this is my function so far:
def bulk_cover_letter(request, ward_id, school_cat_id, cheque_number):
school_type = SchoolType.objects.get(id=school_cat_id)
schools_in_school_type = Applicant.objects.filter(
school_type=school_type, ward_id=ward_id, award_status='awarded'
).order_by().values_list('school_name', flat=True).distinct()
for school in schools_in_school_type:
beneficiaries = Applicant.objects.filter(school_type=school_type, ward_id=ward_id, award_status='awarded', school_name=school)
total_amount_to_beneficiaries = Applicant.objects.filter(school_type=school_type, ward_id=ward_id, award_status='awarded', school_name=school).aggregate(total=Sum('school_type__amount_allocated'))
context = {
'school_name' : school,
'beneficiaries' : beneficiaries,
'total_amount_to_beneficiaries' : total_amount_to_beneficiaries,
'title' : school + ' Disbursement Details',
'cheque_number': cheque_number
}
response = HttpResponse('<title>Cover Letter</title>', content_type='application/pdf')
filename = "%s.pdf" %(cheque_number)
content = "inline; filename=%s" %(filename)
response['Content-Disposition'] = content
template = get_template('cover_letter.html')
html = template.render(context)
result = io.BytesIO()
pdf = pisa.CreatePDF(
html, dest=response, link_callback=link_callback)
if not pdf.error:
# At this point I can generate a single PDF.
# But no idea on what to do next.
# The zipping logic should follow here after looping all the instances - (schools)
From that Point I have no idea on what to do next. Any help will be highly appreciated.
Try this:
Utils.py
def render_to_pdf(template_src, context_dict={}):
template = get_template(template_src)
html = template.render(context_dict)
buffer = BytesIO()
p = pisa.pisaDocument(BytesIO(html.encode("ISO-8859-1")), buffer)
pdf = buffer.getvalue()
buffer.close()
if not p.err:
return pdf#HttpResponse(result.getvalue(), content_type='application/pdf')
return None
def generate_zip(files):
mem_zip = BytesIO()
with zipfile.ZipFile(mem_zip, mode="w",compression=zipfile.ZIP_DEFLATED) as zf:
for f in files:
zf.writestr(f[0], f[1])
return mem_zip.getvalue()
Views.py
def generate_attendance_pdf(modeladmin, request, queryset):
template_path = 'student/pdf_template.html'
files = []
for q in queryset:
context = {
'firstname': q.firstname,
'lastname': q.lastname,
'p_firstname': q.bceID.firstname
}
pdf = render_to_pdf(template_path, context)
files.append((q.firstname + ".pdf", pdf))
full_zip_in_memory = generate_zip(files)
response = HttpResponse(full_zip_in_memory, content_type='application/force-download')
response['Content-Disposition'] = 'attachment; filename="{}"'.format('attendnace.zip')
return response
Obviously, you have to modify the context/names to what you need.
Credit to -> Neil Grogan https://www.neilgrogan.com/py-bin-zip/
If you need to generate several PDF files and send them as a response in a zip file then you can store the reports in memory and set it as dest when you call pisa.CreatePDF. Then have a list of reports in memory, zip them, and send as a Django response specifying another content type.
For example:
reports = tempfile.TemporaryDirectory()
report_files = {}
for school in schools_in_school_type:
# ... same code that renerates `html`
mem_fp = BytesIO()
pisa.CreatePDF(html, dest=mem_fp)
report_files[filename] = mem_fp
mem_zip = BytesIO()
with zipfile.ZipFile(mem_zip, mode="w") as zf:
for filename, content in report_files.items():
zf.write(filename, content)
response = HttpResponse(mem_zip, content_type='application/force-download')
response['Content-Disposition'] = 'attachment; filename="{}"'.format('cover_letters.zip')
This still generates an error of [Errno 2] No such file or directory: 'cheque_number.pdf'.

download PDF with header and footer with Django

I just started to use Django, and I want to create a button that will initiate a PDF download with a header and a footer. for the PDF I use Reportlab. In the Django documentation, they say to use the Canvas object, but I cannot add a footer and a header with canvas. Can anyone give me a piece of code that will return a response from a view in Django with a PDF download with footer and header?
thank you!
Extending BaseDocTemplate allows you to define a Frame contained within a PageTemplate. Flowables are used in the frame so your content can flow over to other pages. The header and footer are just strings of text placed on the Canvas outside of the frame. saveState() and restoreState() have to be used when defining a header and footer so that it repeats on each page of your pdf.
class HeaderFooterTemplate(BaseDocTemplate):
def __init__(self, filename, **kwargs):
self.report_title = kwargs['report_title']
self.pagesize = kwargs['pagesize']
BaseDocTemplate.__init__(self, filename, **kwargs)
main_frame = Frame(
0, 0, self.pagesize[0], self.pagesize[1], topPadding=25, bottomPadding=18, id='main_frame')
template = PageTemplate(id='frame', frames=[main_frame], onPage=self.header_footer)
self.addPageTemplates([template])
def header_footer(self, canv, doc):
canv.saveState()
canv.setPageSize(doc.pagesize)
canv.setTitle(doc.title)
# header
canv.drawCentredString(doc.pagesize[0] / 2, doc.pagesize[1] - 15, self.report_title)
# footer
date_printed = 'Date Printed: ' + dateformat.format(timezone.localtime(timezone.now()), 'Y-m-d f A')
footer_date = canv.beginText(0, 2)
footer_date.textLine(date_printed)
canv.drawText(footer_date)
canv.restoreState()
class PdfTest:
def __init__(self):
self.buffer = BytesIO()
self.pagesize = letter
self.story = []
def build_pdf(self, filename):
"""
Get the value of the BytesIO buffer and write it to the response.
:param filename: name of the file when downloading
"""
pdf = self.buffer.getvalue()
self.buffer.close()
if pdf:
response = HttpResponse(pdf, content_type='application/pdf')
content = 'inline; filename="%s"' % filename
response['Content-Disposition'] = content
return response
def draw(self):
style = styles["Normal"]
for i in range(100):
bogustext = ("This is Paragraph number %s. " % i) *20
p = Paragraph(bogustext, style)
self.story.append(p)
self.story.append(Spacer(1,0.2*inch))
doc = HeaderFooterTemplate(self.buffer, pagesize=self.pagesize, report_title='Test Header Footer PDF')
doc.build(self.story)
return self.build_pdf('test.pdf')
class PdfView(View):
def get(self, request):
pdf = PdfTest()
return pdf.draw()

Create download link file in django

I created a file in project, generation pdf from html. For this i have this method:
def generation_html_to_pdf(self):
path_pdf = None
with NamedTemporaryFile(delete=False, suffix=".pdf", dir='pdf_files') as tf:
path_pdf = tf.name
pdfkit.from_file('templates/first_page.html', tf.name)
return path_pdf
Then, in pdf_files folder i have the pdf file. I want to get a download link for this file:
my view
path_to_pdf = generation_html_to_pdf()
download_link = 'http://' + request.get_host() + path_to_pdf
json_inf_pdf = {'download_link': download_link}
return JsonResponse(json_inf_pdf, status=200)
i have json like this:
{"download_link": "http://127.0.0.1:8000/home/alex/projects/test_project/pdf_files/tmpe0nqbn01.pdf"}"
when i click in this link i have error:
Page not found (404)
You need to create download view and url. Function like this to create link:
def download_link(request):
''' Create download link '''
download_link = 'http://{}/{}'.format(request.get_host(), 'download/my_filename')
json_inf_pdf = {'download_link': download_link}
return JsonResponse(json_inf_pdf, status=200)
and to download pdf:
def download_file(request, my_filename):
''' Download file '''
# Open template
from django.conf import settings
template_url = os.path.join(settings.BASE_DIR, 'templates', 'first_page.html')
template_open = open(template_url, 'r')
# Read template
from django import template
t = template.Template(template_open.read())
c = template.Context({})
# Create pdf
pdf = pdfkit.from_string(t.render(c))
# Create and return response with created pdf
response = HttpResponse(pdf)
response['Content-Type'] = 'application/pdf'
response['Content-disposition'] = 'attachment ; filename = {}'.format(my_filename)
return response
and url:
path('/download/<str:my_filename>', views.download_file, name="download_pdf')
I can't guarantee that this will work in your case without modification, since I can't tell which html-to-pdf library you're using and without seeing your other code. It's just a basic implementation idea.

How to serve a django-webodt file to users?

I'm trying to allow users to export some of their database data. I am using django-webodt to create a .odt file from their data. I then am trying to allow them to download it. The file is created just fine, but when it downloads it seems to download a blank file. I think there is some difference between where the server is looking for the file and where it actually is. I was wondering how to get this to work properly? I'm relatively new to django so any help would be appreciated. The code I have is below:
def downloadBook(request, val):
template = webodt.ODFTemplate('conversion.odt')
context = dict(ideas=Book.objects.getIdeaSet(int(val)))
document = template.render(Context(context))
file_name = os.path.basename(document.name)
path_to_file = os.path.dirname(document.name)
response = HttpResponse(mimetype='application/force-download')
response['Content-Disposition'] = 'attachment; filename=%s' % smart_str(file_name)
response['X-Sendfile'] = smart_str(path_to_file)
return response
I did the following and it works:
from django.template import Context
from webodt import ODFTemplate
template = ODFTemplate('template_file.odt')
context = { 'some_dict': '' }
document = template.render(Context(context))
response = HttpResponse(document.read(), mimetype='application/vnd.oasis.opendocument.text')
response['Content-Disposition'] = "attachment; filename=fancy-filename-as-you-like.odt"
document.close() # delete the document on /tmp
return response

rendering a ReportLab pdf built from SimpleDocTemplate

I've a got a django app that currently generates pdfs using a canvas that the user can download. I create a StringIO buffer, do some stuff and then send call response.write.
# Set up response
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=menu-%s.pdf' % str(menu_id)
# buffer
buff = StringIO()
# Create the pdf object
p = canvas.Canvas(buff)
# Add some elements... then
p.showPage()
p.save()
# Get the pdf from the buffer and return the response
pdf = buff.getvalue()
buff.close()
response.write(pdf)
I now want to build my pdf using platypus and SimpleDocTemplate and have written this
# Set up response
response = HttpResponse(mimetype='application/pdf')
pdf_name = "menu-%s.pdf" % str(menu_id)
response['Content-Disposition'] = 'attachment; filename=%s' % pdf_name
menu_pdf = SimpleDocTemplate(pdf_name, rightMargin=72,
leftMargin=72, topMargin=72, bottomMargin=18)
# container for pdf elements
elements = []
styles=getSampleStyleSheet()
styles.add(ParagraphStyle(name='centered', alignment=TA_CENTER))
# Add the content as before then...
menu_pdf.build(elements)
response.write(menu_pdf)
return response
But this doesn't work, it creates a bad pdf that cannot be opened. I presume the line
response.write(menu_pdf)
is incorrect.
How do I render the pdf?
Your error is actually a pretty simple one. It's just a matter of trying to write the wrong thing. In your code, menu_pdf is not a PDF, but a SimpleDocTemplate, and the PDF has been stored in pdf_name, although here I suspect pdf_name is a path name rather than a file object. To fix it, change your code to use a memory file like you did in your original code:
# Set up response
response = HttpResponse(mimetype='application/pdf')
pdf_name = "menu-%s.pdf" % str(menu_id)
response['Content-Disposition'] = 'attachment; filename=%s' % pdf_name
buff = StringIO()
menu_pdf = SimpleDocTemplate(buff, rightMargin=72,
leftMargin=72, topMargin=72, bottomMargin=18)
# container for pdf elements
elements = []
styles=getSampleStyleSheet()
styles.add(ParagraphStyle(name='centered', alignment=TA_CENTER))
# Add the content as before then...
menu_pdf.build(elements)
response.write(buff.getvalue())
buff.close()
return response
I'm not sure if using file objects rather than paths with Platypus is mentioned in the documentation, but if you dig into the code you'll see that it is possible.
For people who are working with python3 and django 1.7+ some changes to the answer need to be done.
from django.shortcuts import HttpResponse
import io
from reportlab.platypus import SimpleDocTemplate, BaseDocTemplate
def view(request):
buffer = io.BytesIO()
doc = # ... create your SimpleDocTemplate / BaseDocTemplate
# create the usual story
story = []
# ...
doc.build(story)
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename=your_name.pdf'
response.write(buffer.getvalue())
buffer.close()
return response