def pdf_invoice(request, id=None):
# some code
return render_to_pdf(
'voucher_pdf/voucher_pdf.html',
{
'pagesize': page_size,
'title': title,
'init_data': init_data,
}
)
def render_to_pdf(template_src, context_dict):
template = get_template(template_src)
html = template.render(context_dict)
result = BytesIO()
pdf = pisa.CreatePDF(BytesIO(html.encode("ISO-8859-1")), result)
if not pdf.err:
return HttpResponse(result.getvalue(), content_type='application/pdf')
return HttpResponse('We had some errors<pre>%s</pre>' % escape(html))
The pdf print options get populated when I call the pdf_invoice function through url. but I need auto print dialog option.. Is there any solution. If the question is unclear do let me know.
I would suggest something, maybe you can do this "request.get_full_path()" for pdf_invoice's url.
Related
I want to set Password Protected Pages onWeasyPrint PDF Builder.
I am generated PDF using Weasyprint in Django and I want password encrypted after download PDF File.
** Here is code for generate PDF file.**
def build_pdf(request,html_content, header_html=None, footer_html=None):
def get_page_body(boxes):
for box in boxes:
if box.element_tag == "body":
return box
return get_page_body(box.all_children())
def get_page_and_body(html, css):
if html is None:
return None
html = weasyprint.HTML(
string=html,
base_url=getattr(settings, "WEASYPRINT_BASEURL", None),
url_fetcher=django_url_fetcher,
)
css += "#page { margin 0 !important; }"
document = html.render(stylesheets=[weasyprint.CSS(string=css)])
document_page = document.pages[0]
document_body = get_page_body(document_page._page_box.all_children())
return (
document_page,
document_body.copy_with_children(document_body.all_children()),
)
def preprocess_html(html, context):
for key, value in context.items():
html = html.replace(f"{{{{ {key} }}}}", str(value))
return html
document = weasyprint.HTML(
string=html_content,
base_url=request.build_absolute_uri(),
# base_url=getattr(settings, "WEASYPRINT_BASEURL", None),
url_fetcher=django_url_fetcher,
).render()
return document.write_pdf()
can anyone help me?
so i have this two views, one used to display information and one that returns a file responde. I am trying to download a pdf file using the information on the first view:
#login_required()
def detail(request, location_name):
if request.method == "POST":
return search_in_employees(request)
current = CurrentInfo()
pdf_data = current.detail_employees_by_location(location_name) # this gives me the list of people
context = {
'present': current.detail_employees_by_location(location_name),
'location': location_name,
}
print('Data: -------------->', pdf_data)
return render(request, 'user_area/detail.html', context)
and my second view just formats it as a pdf:
#login_required()
def download_pdf(request):
buf = io.BytesIO()
canv = canvas.Canvas(buf, pagesize=letter, bottomup=0)
textob = canv.beginText()
textob.setTextOrigin(inch, inch)
textob.setFont("Helvetica", 14)
lines = [
"Line 1 ",
"Line 2 ",
"Line 3 ",
"Line 4 ",
]
for line in lines:
textob.textLine(line)
canv.drawText(textob)
canv.showPage()
canv.save()
buf.seek(0)
return FileResponse(buf, as_attachment=True, filename='employees.pdf')
Right now the PDF file only contains dummy data, but how can i pass pdf_data from the first view to the second?
I would suggest creating a function either inside your views.py or inside a helpers.py file in your module:
def get_pdf_data(location_name):
current = CurrentInfo()
pdf_data = current.detail_employees_by_location(location_name)
return pdf_data
Then your first view would look like:
#login_required()
def detail(request, location_name):
if request.method == "POST":
return search_in_employees(request)
pdf_data = get_pdf_data(location_name)
context = {
'present': pdf_data,
'location': location_name,
}
print('Data: -------------->', pdf_data)
return render(request, 'user_area/detail.html', context)
And your second view can use this new function but only if you send the location_name to the view same as the first view
#login_required()
def download_pdf(request, location_name):
pdf_data = get_pdf_data(location_name)
buf = io.BytesIO()
canv = canvas.Canvas(buf, pagesize=letter, bottomup=0)
textob = canv.beginText()
textob.setTextOrigin(inch, inch)
textob.setFont("Helvetica", 14)
for line in pdf_data:
textob.textLine(line)
canv.drawText(textob)
canv.showPage()
canv.save()
buf.seek(0)
return FileResponse(buf, as_attachment=True, filename='employees.pdf')
Im new in Django,
I'm using xhtml2pdf for rendering data objects from template to PDF file , and i want to allow users to render only checked objects by checkboxes into pdf, is there anyway to filter that in Django ?
Thanks
views.py :
def render_to_pdf(template_src, context_dict={}):
template = get_template(template_src)
html = template.render(context_dict)
result = BytesIO()
pdf = pisa.pisaDocument(BytesIO(html.encode('ISO-8859-1')), result, link_callback=link_callback)
if pdf.err:
return HttpResponse('Error')
return HttpResponse(result.getvalue(), content_type='application/pdf')
class ViewPDF(View):
#method_decorator(login_required(login_url='livraison:login_page'))
def get(self, request, *args, **kwargs):
checked_objects = [i dont know how to get them]
queryset = Livraison.objects.filter(id__in=[checked_objects]) # i want something does that
data = {
'livraisons' : queryset,
'now' : f'Livraisons-{date.today()}'
}
pdf = render_to_pdf('pdf_template.html', data)
return HttpResponse(pdf, content_type='application/pdf')
use forms to get user data.
class LivraisonSelectForm(forms.Form):
livraison = forms.ModelChoiceField(label='select', queryset=Livraison.objects.all(), widget=forms.CheckboxInput())
then use it in your view:
class ViewPDF(FormView):
form_class = LivraisonSelectForm
template_name = 'path_to_template_with_html_to_filter_data'
#method_decorator(login_required(login_url='livraison:login_page'))
def form_valid(self, form):
checked_objects = form.cleaned_data.get('livraison', [])
queryset = Livraison.objects.filter(id__in=checked_objects) # i want something does that
data = {
'livraisons' : queryset,
'now' : f'Livraisons-{date.today()}'
}
pdf = render_to_pdf('pdf_template.html', data)
return HttpResponse(pdf, content_type='application/pdf')
and don't forget to show this form in your html {{ form }}
**
UPDATE
**
I Found a solution , i used Ajax code to collect every selected object
// check selected objects (#pdf is the id of the button which gonna generate the pdf file)
$('#pdf').click(function () {
var id = [];
$(':checkbox:checked').each(function (i) {
id[i] = $(this).val()
})
if (id.length === 0) {
alert('Please Select something..');
} else {
$.ajax({
url: '.',
method: 'GET',
data: {
id,
},
success: function (response) {
console.log('PDF is ready')
}
})
}
});
then i ad the variable into the view function to collect the selected objects and filter the queryset
myFunction.selected_ones = request.GET.getlist('id[]')
then filter queryset in the generated_pdf_func
queryset = MODEL.objects.filter(id__in=[x for x in myFunction.selected_ones if x != '0'])
NOTE : <if x != '0'> is important in case you want to select all because it returns 0 and you don't have any id = 0 in the DB
I need to let the Django auto download the generated file.
Tried all different solutions online, none of them works.
Views.py
def validate(request):
if request.method == 'POST':
filename = request.POST.get('source_file')
file_path = os.path.join(settings.MEDIA_ROOT, 'SourceFiles', filename)
region = request.POST.get('region')
product_type = request.POST.get('product_type')
result = validateSource.delay(file_path, region, product_type)
output_filepath, log_filepath = result.get()
if os.path.exists(output_filepath) and os.path.exists(log_filepath):
zip_filename = zipFiles([output_filepath, log_filepath], filename)
zip_filepath = os.path.join(settings.MEDIA_ROOT, zip_filename)
response = FileResponse(open(zip_filepath, 'rb'), as_attachment=True)
return response
raise Http404
Template: code for the form POST.
$(document).on('submit', '#productForm', function(e){
e.preventDefault();
var inputFilePath = document.getElementById('sourceFileInput').files.item(0).name;
$.ajax({
method: 'POST',
url: 'validate/',
data: {
source_file: inputFilePath,
region: $("#Region-choice").val(),
product_type: $("#Product-type").val()}
})
.done(function(){
document.getElementById('lblStatus').innerHTML = "Result: <br/>"
document.getElementById('lblStatusContent').innerHTML = "Success!"
})
.fail(function(req, textStatus, errorThrown) {
document.getElementById('lblStatus').innerHTML = "Result: <br/>"
alert("Something went wrong!:" + textStatus + ' ' + errorThrown )
});
});
});
It's not possible to download files to your computer via an ajax (XHR) request. So you need to redirect the user actually (setting window.location) to a view that downloads the file. Or you can add as a result of the successful POST a button the current page so the user can download the file. In any case, you need to move the file download to a different view so a standard GET request can fetch it.
But your code to return the file in Django (using FileResponse) is correct.
There's also an explanation with an alternative way of doing it here
def validate(request):
if request.method == 'POST':
filename = request.POST.get('source_file')
file_path = os.path.join(settings.MEDIA_ROOT, 'SourceFiles', filename)
region = request.POST.get('region')
product_type = request.POST.get('product_type')
result = validateSource.delay(file_path, region, product_type)
output_filepath, log_filepath = result.get()
if os.path.exists(output_filepath) and os.path.exists(log_filepath):
zip_filename = zipFiles([output_filepath, log_filepath], filename)
zip_filepath = os.path.join(settings.MEDIA_ROOT, zip_filename)
with open(zip_filepath, 'rb') as fh:
response = HttpResponse(fh.read(), content_type="application/force-download")
response['Content-Disposition'] = 'attachment; filename=' + os.path.basename(zip_filepath)
return response
raise Http404
I'm attempting to render a PDF and populate the template with specific data from the object that is being viewed.
I'm using xhtml12pdf / pisa. I've successfully rendered a generic (unpopulated) PDF, however when I add logic to populate a specific object's data, my context is being returned however the pdf is no longer being rendered.
views.py
class GeneratePdf(DetailView):
model = Request
template_name='request_response/response.html'
def get(self, request, *args, **kwargs):
context = super(GeneratePdf,self).get(request,*args,**kwargs)
return context
pdf = render_to_pdf('request_response/response.html',context)
if pdf:
response = HttpResponse(pdf,content_type='application/pdf')
filename = "PrivacyRequest_%s.pdf" %("1234")
content = "inline; filename='%s'" %(filename)
response['Content-Disposition'] = content
return response
return HttpResponse("Not Found")
Please show your render_to_pdf function. I assume that it like:
from io import BytesIO
from xhtml2pdf import pisa
from django.template.loader import get_template
def render_to_pdf(template, context):
template = get_template(template)
html = template.render(context)
result = BytesIO()
pdf = pisa.pisaDocument(BytesIO(html.encode("UTF-8")), result)
if not pdf.err:
return HttpResponse(result.getvalue(), content_type='application/pdf')
return None
You can remove context = super(GeneratePdf,self).get(request,*args,**kwargs) and return context.
As shown in the error message, context must be a dict. So change it to dictionary, like:
def get(self, request, *args, **kwargs):
context = {
'example1': 'This is example 1',
'some_foo': 'So many of foo function'
}
pdf = render_to_pdf('request_response/response.html',context)
if pdf:
response = HttpResponse(pdf,content_type='application/pdf')
filename = "PrivacyRequest_%s.pdf" %("1234")
content = "inline; filename='%s'" %(filename)
response['Content-Disposition'] = content
return response
return HttpResponse("Not Found")
FYI: This is another similiar question like yours and it has accepted answer.