重写get_template_names的DRF视图会引发ValueError

时间:2017-07-09 12:56:05

标签: django django-rest-framework

从2013年开始this ticket表示:

  

。当在ViewSet内部时,将设置.action属性,以触发任何一个动作(例如列表)。如果你在一个方法中,例如get_template_names,你可以使用它,并且需要访问正在处理的任何一个动作。

但是,当我尝试进行一个简单的实验时:

class ExampleViewSet(viewsets.ModelViewSet):
    """
    A viewset for the example model.
    """
    queryset = Example.objects.all()
    serializer_class = ExampleSerialiser

    def get_template_names(self):
        if self.action == 'list':
            return ['example/list_examples.html']

使用设置:

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.TemplateHTMLRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
        'rest_framework.renderers.JSONRenderer'
    ),
}

我明白了:

Internal Server Error: /example/
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/exception.py", line 39, in inner
    response = get_response(request)
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 217, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 215, in _get_response
    response = response.render()
  File "/usr/local/lib/python2.7/dist-packages/django/template/response.py", line 109, in render
    self.content = self.rendered_content
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/response.py", line 72, in rendered_content
    ret = renderer.render(self.data, accepted_media_type, context)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/renderers.py", line 174, in render
    return template_render(template, context, request=request)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/compat.py", line 279, in template_render
    return template.render(context, request=request)
  File "/usr/local/lib/python2.7/dist-packages/django/template/backends/django.py", line 64, in render
    context = make_context(context, request, autoescape=self.backend.engine.autoescape)
  File "/usr/local/lib/python2.7/dist-packages/django/template/context.py", line 267, in make_context
    context.push(original_context)
  File "/usr/local/lib/python2.7/dist-packages/django/template/context.py", line 59, in push
    return ContextDict(self, *dicts, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/django/template/context.py", line 18, in __init__
    super(ContextDict, self).__init__(*args, **kwargs)
ValueError: dictionary update sequence element #0 has length 4; 2 is required

从浏览源代码看,get_template_names似乎会返回一个可迭代的。

我做错了什么?

更新:

将Django升级到最新版本会将异常更改为更明显的类型:TypeError:

Internal Server Error: /example/
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 217, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 215, in _get_response
    response = response.render()
  File "/usr/local/lib/python2.7/dist-packages/django/template/response.py", line 107, in render
    self.content = self.rendered_content
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/response.py", line 72, in rendered_content
    ret = renderer.render(self.data, accepted_media_type, context)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/renderers.py", line 176, in render
    return template_render(template, context, request=request)
  File "/usr/local/lib/python2.7/dist-packages/rest_framework/compat.py", line 340, in template_render
    return template.render(context, request=request)
  File "/usr/local/lib/python2.7/dist-packages/django/template/backends/django.py", line 64, in render
    context = make_context(context, request, autoescape=self.backend.engine.autoescape)
  File "/usr/local/lib/python2.7/dist-packages/django/template/context.py", line 287, in make_context
    raise TypeError('context must be a dict rather than %s.' % context.__class__.__name__)
TypeError: context must be a dict rather than ReturnList.
[09/Jul/2017 13:22:26] "GET /example/ HTTP/1.1" 500 91963

上下文似乎是OrderedDicts数组:

/usr/local/lib/python2.7/dist-packages/rest_framework/compat.py in template_render
        return template.render(context, request=request) ...
▼ Local vars
context [OrderedDict([(u'url', u'http://127.0.0.1:8080/example/1/'), ('created', u'2017-06-26T19:48:08.980344Z'), ('updated', u'2017-07-08T21:54:28.505181Z'), ('name', u'Example 1')]), OrderedDict([(u'url', u'http://127.0.0.1:8080/example/2/'), ('created', u'2017-06-26T21:45:36.310536Z'), ('updated', u'2017-06-26T21:45:36.310636Z'), ('name', u'Example 2')]), OrderedDict([(u'url', u'http://127.0.0.1:8080/example/3/'), ('created', u'2017-06-26T21:46:00.390582Z'), ('updated', u'2017-06-26T21:46:00.390620Z'), ('name', u'Example 3')]), OrderedDict([(u'url', u'http://127.0.0.1:8080/example/4/'), ('created', u'2017-06-26T21:46:07.777296Z'), ('updated', u'2017-06-26T21:46:07.777335Z'), ('name', u'Example 4')])]
request <rest_framework.request.Request object at 0x7f027aa31cd0>
templat <django.template.backends.django.Template object at 0x7f027aa31190>

似乎情况正在发生。

第二次更新

所以,我最初认为这与get_template_names有关,这是错误的。显然它与它无关。这似乎与使用ViewHTets和TemplateHTMLRenderer有关。这是否按预期工作?

来自docs

  

TemplateHTMLRenderer类要求响应包含上下文数据字典,并根据必须在视图或响应中指定的模板呈现HTML页面。

     

StaticHTMLRender类要求响应包含一个字符串   预呈现的HTML内容。

     

因为静态HTML页面通常具有与API不同的行为   您可能需要明确地编写任何HTML视图的响应,   而不是依赖于内置的通用视图。

对于我所知道的记录,并且一直在使用覆盖方法的格式,如:

def list(self, request, **kwargs):
    if request.accepted_renderer.format == 'html':
        examples = {'examples': self.get_queryset()}
        return Response(examples, template_name='example/list_examples.html')

    return super(ExampleViewSet, self).list(self, request, **kwargs)

但是,我原本以为这主要是为了明确你要在视图上呈现哪个模板。为了避免覆盖所有这些方法,我希望使用get_template_names方法。

0 个答案:

没有答案