在Django中协商内容的最小样板量是多少?

时间:2012-04-18 00:10:16

标签: python django

在Django应用程序中,我有一些返回JSON的视图,调用类似于:

return HttpResponse(json.dumps(content), mimetype="application/json")

我想开始创建返回HTML或JSON的视图,具体取决于请求中的Accept标头。也可能是其他类型,但那些是主要的类型。我还希望将多个URL路由到此视图;文件扩展名“.html”和“.json”在发出请求时帮助告诉客户他们应该Accept哪种类型,我想避免使用“?format = json”反模式。

使用最少的样板或重复代码在Django中执行此操作的正确,有福的方法是什么?

(编辑:改编,以便更好地遵循SO的社区准则。)

3 个答案:

答案 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。)