2

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

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

我想开始创建根据Accept请求的标头返回 HTML 或 JSON 的视图。可能还有其他类型,但这些是主要类型。我还想将多个 URL 路由到这个视图;文件扩展名“.html”和“.json”有助于告诉客户在提出请求时应该使用哪些类型Accept,我想避免使用“?format=json”反模式。

在 Django 中使用最少的样板代码或重复代码来做到这一点的正确、幸运的方法是什么?

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

4

3 回答 3

2

我认为基于类的视图混合(django 1.3+)是最简单的方法。您的所有视图都将继承自一个基类,该基类包含响应相应内容的逻辑。

于 2012-04-18T04:19:01.147 回答
1

我想我可能在这里看不到你的大局,但这就是我要做的:

有一个 html 模板,在请求 html 时呈现,并在json.dumps(content)请求 json 时保留你的 for。似乎很明显,但我想我还是应该提一下。

设置您的 URL 以发送给您"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)

我知道这有点含糊,因为我还没有完全考虑清楚,但这是我要开始的地方。

于 2012-04-18T01:00:33.027 回答
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

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

于 2013-07-24T11:48:06.730 回答