在Django应用程序中,我有一些返回JSON的视图,调用类似于:
return HttpResponse(json.dumps(content), mimetype="application/json")
我想开始创建返回HTML或JSON的视图,具体取决于请求中的Accept
标头。也可能是其他类型,但那些是主要的类型。我还希望将多个URL路由到此视图;文件扩展名“.html”和“.json”在发出请求时帮助告诉客户他们应该Accept
哪种类型,我想避免使用“?format = json”反模式。
使用最少的样板或重复代码在Django中执行此操作的正确,有福的方法是什么?
(编辑:改编,以便更好地遵循SO的社区准则。)
答案 0 :(得分:2)
我认为class-based view mixin(django 1.3+)是最简单的方法。您的所有视图都将从包含用适当内容进行响应的逻辑的基类继承。
答案 1 :(得分:1)
我想我可能不会在这里看到你的大图,但这就是我要做的事情:
在请求html时有一个html模板,并在请求json时保留json.dumps(content)
。似乎很明显,但我想我还是应该提一下。
设置您的网址,以便向您发送"json"
或'html'
。 :
(r'^some/path/(?P<url_path>.*)\.(?P<extension>html|json)$', 'some.redirect.view'),
(r'^/(?P<extension>html|json)/AppName', include(MyApp)),
# etc etc
和您的观点:
def myRedirectView(request, url_path, extension):
view, args, kwargs = resolve("/" + extension + "/" + urlPath)
kwargs['request'] = request
return view(*args, **kwargs)
我知道这有点模糊,因为我没有完全考虑过,但我会从哪里开始。
答案 2 :(得分:0)
我已经通过创建一个基于Django自己的generic.View类的通用视图类来解决这个问题,它定义了一个装饰器'accept_types'。这将修改应用它的视图,以便在指示的内容类型不在Accept标头中时返回None。然后,get()方法(由generic.View调度程序调用)如下所示:
def get(self, request):
self.request = request # For clarity: generic.View does this anyway
resultdata = { 'result': data, etc. }
return (
self.render_uri_list(resultdata) or
self.render_html(resultdata) or
self.error(self.error406values())
)
实际的视图渲染器因此被装饰:
@ContentNegotiationView.accept_types(["text/uri-list"])
def render_uri_list(self, resultdata):
resp = HttpResponse(status=200, content_type="text/uri-list")
# use resp.write(...) to assemble rendered response body
return resp
@ContentNegotiationView.accept_types(["text/html", "application/html", "default_type"])
def render_html(self, resultdata):
template = loader.get_template('rovserver_home.html')
context = RequestContext(self.request, resultdata)
return HttpResponse(template.render(context))
声明装饰器的(一次性)通用视图类如下所示:
class ContentNegotiationView(generic.View):
"""
Generic view class with content negotiation decorators and generic error value methods
Note: generic.View dispatcher assigns HTTPRequest object to self.request.
"""
@staticmethod
def accept_types(types):
"""
Decorator to use associated function to render the indicated content types
"""
def decorator(func):
def guard(self, values):
accept_header = self.request.META.get('HTTP_ACCEPT',"default_type")
accept_types = [ a.split(';')[0].strip().lower()
for a in accept_header.split(',') ]
for t in types:
if t in accept_types:
return func(self, values)
return None
return guard
return decorator
(装饰器中的参数处理应该是通用的 - 这段代码可以工作,但是在我写这篇文章时仍在开发中。实际的代码在https://github.com/wf4ever/ro-manager/tree/develop/src/roverlay/rovweb/rovserver的GitHub中,但是在适当的时候应该分成一个单独包装.HTH。)