我已经通过创建一个基于 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
(装饰器中的参数处理应该是通用的——这段代码有效,但在我写这篇文章时仍在开发中。实际代码在 GitHub 中https://github.com/wf4ever/ro-manager/tree/develop/ src/roverlay/rovweb/rovserver,但在适当的时候应该分开到一个单独的包中。HTH。)