我们对大多数项目使用基于类的视图。当我们尝试创建一个CSV Mixin时,我们遇到了一个问题,它允许用户将来自几乎任何页面的信息导出为CSV文件。我们的特殊问题涉及CSV文件,但我相信我的问题通用性足以与任何文件类型相关。
我们遇到的问题是视图的响应是试图转到模板(比如from django.views.generic import TemplateView
)。我们在urls.py
文件中指定模板。
url(r'^$', MyClassBasedView.as_view(template_name='my_template.html'))
如何强制响应绕过模板并返回标准HttpResponse
?我猜你需要覆盖一个方法,但我不确定是哪一个。
有什么建议吗?
EDIT1:我似乎不清楚我们要做什么。我已经渲染了一个页面(通过基于类的视图),用户将看到信息报告。我需要输入一个“导出到CSV”按钮供用户按,它将在页面上导出信息并将CSV下载到他们的机器上。
不能将视图重写为基于方法的视图。我们处理几乎所有基于类的视图类型(DetailView,ListView,TemplateView,View,RedirectView等)
答案 0 :(得分:13)
当您需要为相同数据提供不同的响应时,这是一个常见问题。您想要插入的点是当上下文数据已经解决但尚未构建响应时。
解析为TemplateResponseMixin
的基于类的视图具有多个属性和类方法,用于控制响应对象的构造方式。不要认为名称暗示只有HTML响应或那些需要模板处理的人才能通过这种设计来促进。解决方案包括创建基于TemplateResponse
类行为的自定义可重用响应类,或创建可为render_to_response
方法提供自定义行为的可重用mixin。
除了编写自定义响应类之外,开发人员更经常在视图类上提供自定义render_to_response
方法,或者在mixin中单独提供,因为它非常简单明了地计算出正在发生的事情。您将嗅探请求数据以查看是否必须构造某种不同类型的响应,如果不是,您只需委托默认实现来呈现模板响应。
以下是一个这样的实现可能如下所示:
import csv
from django.http import HttpResponse
from django.utils.text import slugify
from django.views.generic import TemplateView
class CSVResponseMixin(object):
"""
A generic mixin that constructs a CSV response from the context data if
the CSV export option was provided in the request.
"""
def render_to_response(self, context, **response_kwargs):
"""
Creates a CSV response if requested, otherwise returns the default
template response.
"""
# Sniff if we need to return a CSV export
if 'csv' in self.request.GET.get('export', ''):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="%s.csv"' % slugify(context['title'])
writer = csv.writer(response)
# Write the data from the context somehow
for item in context['items']:
writer.writerow(item)
return response
# Business as usual otherwise
else:
return super(CSVResponseMixin, self).render_to_response(context, **response_kwargs):
在这里,您还可以看到何时可能需要使用自定义响应类的更复杂的设计。虽然这对于为自定义响应类型添加临时支持非常有效,但如果您想支持五种不同的响应类型,它就无法很好地扩展。
在这种情况下,您将创建并测试单独的响应类并编写单个CustomResponsesMixin
类,该类将了解所有响应类并提供仅配置{{1}的自定义render_to_response
方法并将其他所有内容委托给响应类。
答案 1 :(得分:1)
如何强制响应绕过模板并返回 一个标准的HttpResponse?
这有点违背使用TemplateView
的要点。如果你想要返回的东西不是模板化的反应,那么它应该是一个不同的观点。
...然而
我猜你需要覆盖一个方法,但我不确定是哪一个。
...如果您希望将其破解为现有的TemplateView
,请从源代码中注明...
class TemplateView(TemplateResponseMixin, ContextMixin, View):
"""
A view that renders a template. This view will also pass into the context
any keyword arguments passed by the url conf.
"""
def get(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
return self.render_to_response(context)
...因此您必须覆盖get()
方法,以便在返回CSV时不会调用render_to_response()
。例如......
class MyClassBasedView(TemplateView):
def get(self, request, *args, **kwargs):
if request.GET['csv'].lower() == 'true':
# Build custom HTTP response
return my_custom_response
else:
return TemplateView.get(request, *args, **kwargs)
如果你需要View
的所有子类的通用mixin,我想你可以做类似......
class MyMixin(object):
def dispatch(self, request, *args, **kwargs):
if request.GET['csv'].lower() == 'true':
# Build custom HTTP response
return my_custom_response
else:
return super(MyMixin, self).dispatch(request, *args, **kwargs)
class MyClassBasedView(MyMixin, TemplateView):
pass