SecNot

jul 12, 2015

Vista para la descarga de archivos generados dinámicamente

Hoy he estado programando en Django una vista para la descarga de informes, en la que los usuarios registrados de una página pueden pedir un informe de la actividad para un determinado año. La particularidad es que esos informes se generan de forma dinámica en el momento de la petición, nada complicado pero antes de empezar a programar he buscado que paquetes había disponibles, y me he encontrado django-downloadview. Con eso y un poco de código extra para comprobar que el usuario está autenticado he solucionado el problema. Algunas veces CBV parecen magia.

#views.py
from django.shortcuts import render
from django.core.files.base import ContentFile
from django_downloadview import VirtualDownloadView
from django.http import HttpResponseForbidden, HttpResponseServerError


class LoginRequiredMixin(object):

    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_authenticated():
            return HttpResponseForbidden()
        else:
            return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)


class DownloadReportView(LoginRequiredMixin, VirtualDownloadView):

    def generar_report(self, user, year):
        # Generar contenido del informe para el usuario y fecha
        return "Report content for {} {}".format(user.username, year)

    def get_file(self):
        # Metodo de VirtualDownloadView que devuelve el archivo virtual
        report_name = 'report.txt'
        return ContentFile(self.report_content, name=report_name)

    def get(self, request, *args, **kwargs):

        report_year = kwargs.get('year', None)

        # El contenido del informe se genera aquí en lugar de en get_file, para
        # simplificar la
        try:
            self.report_content=self.generate_report(request.user, report_year)
        except Exception:
            return HttpResponseServerError("There was an error while generating the report")

        return super(DownloadReportView, self).get(request, *args, **kwargs)

Y el archivo urls.py para quien le pueda interesar:

#urls.py
from django.conf.urls import url
from .views import DownloadReportView

urlpatterns = [
        url( # Handle report downloads
                regex = r'^download_report/(?P<year>[0-9]{4})$',
                view  = DownloadReportView.as_view(),
                name  = 'download_user_report'),
]