from teleforma.views.core import *
from django.utils.translation import ugettext_lazy as _
+from django.template import loader, Context, RequestContext
+from django.views.generic.base import TemplateResponseMixin
+from django.http import HttpResponse
+from django.conf import settings
+from django.shortcuts import render
+from django.template.loader import get_template
+from django.template.context import Context
+from django.utils.html import escape
+from django.views.generic.detail import SingleObjectMixin
+
+import os
+from cgi import escape
+from cStringIO import StringIO
+
+from xhtml2pdf import pisa
from forms_builder.forms.forms import FormForForm
from forms_builder.forms.models import Form
from forms_builder.forms.signals import form_invalid, form_valid
+def content_to_pdf(content, dest, encoding='utf-8', **kwargs):
+ """
+ Write into *dest* file object the given html *content*.
+ Return True if the operation completed successfully.
+ """
+ from xhtml2pdf import pisa
+ src = StringIO(content.encode(encoding))
+ pdf = pisa.pisaDocument(src, dest, encoding=encoding, **kwargs)
+ return not pdf.err
+
+def content_to_response(content, filename=None):
+ """
+ Return a pdf response using given *content*.
+ """
+ response = HttpResponse(content, mimetype='application/pdf')
+ if filename is not None:
+ response['Content-Disposition'] = 'attachment; filename=%s' % filename
+ return response
+
+def render_to_pdf(request, template, context, filename=None, encoding='utf-8',
+ **kwargs):
+ """
+ Render a pdf response using given *request*, *template* and *context*.
+ """
+ if not isinstance(context, Context):
+ context = RequestContext(request, context)
+
+ content = loader.render_to_string(template, context)
+ buffer = StringIO()
+
+ succeed = content_to_pdf(content, buffer, encoding, **kwargs)
+ if succeed:
+ return content_to_response(buffer.getvalue(), filename)
+ return HttpResponse('Errors rendering pdf:<pre>%s</pre>' % escape(content))
+
+
def get_seminars(user):
seminars = []
return render_to_response(template, context, request_context)
-# Testimonials
-import StringIO
-
-from xhtml2pdf import pisa
-
-from django.conf import settings
-from django.http import HttpResponse
-from django.shortcuts import render
-from django.template.loader import get_template
-from django.template.context import Context
-from django.utils.html import escape
-from django.views.generic.detail import SingleObjectMixin
+class PDFTemplateResponseMixin(TemplateResponseMixin):
+ """
+ Mixin for Django class based views.
+ Switch normal and pdf template based on request.
+ The switch is made when the request has a particular querydict, e.g.::
-class TestimonialView(DetailView):
+ http://www.example.com?format=pdf
- model = Seminar
- template_name = 'teleforma/seminar_detail.html'
- mimetype = 'application/pdf'
- extension = 'pdf'
+ The key and value of the querydict can be overridable using *as_view()*.
+ That pdf url will be present in the context as *pdf_url*.
- @method_decorator(login_required)
- def dispatch(self, *args, **kwargs):
- return super(TestimonialView, self).dispatch(*args, **kwargs)
-
- def get_context_data(self, **kwargs):
- context = super(TestimonialView, self).get_context_data(**kwargs)
- context['seminar'] = self.get_object()
- return context
-
- def download(self, request, pk):
- """Function to render html template into a pdf file"""
+ For example it is possible to define a view like this::
- seminar = Seminar.objects.get(id=pk)
- template = get_template(self.template_name)
-
- context = Context({'seminar': seminar, 'STATIC_URL': settings.STATIC_ROOT })
- html = template.render(context)
- result = StringIO.StringIO()
-
- pdf = pisa.pisaDocument(StringIO.StringIO(html.encode("UTF-8")),
- dest=result,
- encoding='UTF-8',
- link_callback=self.fetch_resources)
- if not pdf.err:
- response = HttpResponse(result.getvalue(), mimetype=self.mimetype)
- return response
+ from django.views.generic import View
- return HttpResponse('We had some errors<pre>%s</pre>' % escape(html))
+ class MyView(PDFTemplateResponseMixin, View):
+ template_name = 'myapp/myview.html'
+ pdf_filename = 'report.pdf'
-
+ The pdf generation is automatically done by *xhtml2pdf* using
+ the *myapp/myview_pdf.html* template.
+ Note that the pdf template takes the same context as the normal template.
+ """
+ pdf_template_name = None
+ pdf_template_name_suffix = '_pdf'
+ pdf_querydict_key = 'format'
+ pdf_querydict_value = 'pdf'
+ pdf_encoding = 'utf-8'
+ pdf_filename = None
+ pdf_url_varname = 'pdf_url'
+ pdf_kwargs = {}
+
+ def is_pdf(self):
+ value = self.request.REQUEST.get(self.pdf_querydict_key, '')
+ return value.lower() == self.pdf_querydict_value.lower()
+
+ def _get_pdf_template_name(self, name):
+ base, ext = os.path.splitext(name)
+ return '%s%s%s' % (base, self.pdf_template_name_suffix, ext)
+
+ def get_pdf_template_names(self):
+ """
+ If the template name is not given using the class attribute
+ *pdf_template_name*, then it is obtained using normal template
+ names, appending *pdf_template_name_suffix*, e.g.::
+ path/to/detail.html -> path/to/detail_pdf.html
+ """
+ if self.pdf_template_name is None:
+ names = super(PDFTemplateResponseMixin, self).get_template_names()
+ return map(self._get_pdf_template_name, names)
+ return [self.pdf_template_name]
- def fetch_resources(self, uri, rel):
+ def get_pdf_filename(self):
"""
- Callback to allow xhtml2pdf/reportlab to retrieve Images,Stylesheets, etc.
- `uri` is the href attribute from the html link element.
- `rel` gives a relative path, but it's not used here.
+ Return the pdf attachment filename.
+ If the filename is None, the pdf will not be an attachment.
+ """
+ return self.pdf_filename
+ def get_pdf_url(self):
"""
- if uri.startswith(settings.MEDIA_URL):
- path = os.path.join(settings.MEDIA_ROOT,
- uri.replace(settings.MEDIA_URL, ""))
- elif uri.startswith(settings.STATIC_URL):
- path = os.path.join(settings.STATIC_ROOT,
- uri.replace(settings.STATIC_URL, ""))
- else:
- path = os.path.join(settings.STATIC_ROOT,
- uri.replace(settings.STATIC_URL, ""))
+ This method is used to put the pdf url in the context.
+ """
+ querydict = self.request.GET.copy()
+ querydict[self.pdf_querydict_key] = self.pdf_querydict_value
+ return '%s?%s' % (self.request.path, querydict.urlencode())
+
+ def get_pdf_response(self, context, **response_kwargs):
+ return render_to_pdf(
+ request=self.request,
+ template=self.get_pdf_template_names(),
+ context=context,
+ encoding=self.pdf_encoding,
+ filename=self.get_pdf_filename(),
+ **self.pdf_kwargs
+ )
+
+ def render_to_response(self, context, **response_kwargs):
+ if self.is_pdf():
+ from django.conf import settings
+ context['STATIC_ROOT'] = settings.STATIC_ROOT
+ return self.get_pdf_response(context, **response_kwargs)
+ context[self.pdf_url_varname] = self.get_pdf_url()
+ return super(PDFTemplateResponseMixin, self).render_to_response(
+ context, **response_kwargs)
- if not os.path.isfile(path):
- path = os.path.join(settings.MEDIA_ROOT,
- uri.replace(settings.MEDIA_URL, ""))
- if not os.path.isfile(path):
- raise UnsupportedMediaPathException(
- 'media urls must start with %s or %s' % (
- settings.MEDIA_ROOT, settings.STATIC_ROOT))
-
- return path
+class TestimonialView(PDFTemplateResponseMixin, SeminarView):
+
+ model = Seminar
+ template_name = 'teleforma/seminar_testimonial.html'
+ pdf_template_name = 'teleforma/seminar_testimonial.html'
+ # pdf_filename = 'report.pdf'
+
+
+ @method_decorator(login_required)
+ def dispatch(self, *args, **kwargs):
+ return super(TestimonialView, self).dispatch(*args, **kwargs)
+
+ def get_context_data(self, **kwargs):
+ context = super(TestimonialView, self).get_context_data(**kwargs)
+ context['seminar'] = self.get_object()
+ return context