Django Rest Framework:我的默认渲染器发生了什么? [英] Django Rest Framework: what happened to my default Renderer?

查看:42
本文介绍了Django Rest Framework:我的默认渲染器发生了什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想调用/contacts/1.json返回json,调用1.api返回browsableAPI,并调用format = None / aka / contacts / 1 /返回一个模板,我们将其称为render_form。这样,最终用户可以拥有漂亮的表格,开发人员可以使用.api格式,而ajax / apps等使用.json。似乎是一个普通的用例,但在DRF中我没有点击...

I would like calls to /contacts/1.json to return json, 1.api to return browsableAPI, and calls with format=None aka /contacts/1/ to return a template where we call render_form. This way end-users can have pretty forms, and developers can use the .api format, and ajax/apps etc use .json. Seems like a common use case but something isn't clicking for me here in DRF...

在没有给出格式的情况下,DRF如何确定使用的渲染器仍在挣扎。我发现然后在堆栈交换上丢失了一些信息,这些信息基本上说是根据格式拆分响应。添加TemplateHTMLRenderer会引起各种麻烦。我曾尝试根据格式进行拆分,但这在下面给了我JSON错误。

Struggling with how DRF determines the Renderer used when no format is given. I found and then lost some info here on stack exchange that basically said to split the responses based on format. Adding the TemplateHTMLRenderer caused all sorts of pain. I had tried to split based on format but that is giving me JSON error below.

我不知道定义应使用哪种渲染器的实际方法。尤其是当没有提供格式时。我的意思是,使用Response(data)时,它有效。而且我可以让TemplateHTMLRenderer正常工作,但要以没有默认渲染器为代价。

I don't understand the de facto way to define what renderer should be used. Especially when no format is provided. I mean, it "just works" when using Response(data). And I can get the TemplateHTMLRenderer to work but at the cost of having no default Renderer.

GET / contacts / 1 /给出错误:
<联系人:联系人对象>不是JSON可序列化的

GET /contacts/1/ Gives the error: <Contact: Contact object> is not JSON serializable

使用此代码:

class ContactDetail(APIView):
permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                      IsOwnerOrReadOnly,)
queryset = Contact.objects.all()
renderer_classes = (BrowsableAPIRenderer, JSONRenderer, TemplateHTMLRenderer,)

"""
Retrieve, update or delete a contact instance.
"""
def get_object(self, pk):
    try:
        return Contact.objects.get(pk=pk)
    except Contact.DoesNotExist:
        raise Http404

def get(self, request, pk, format=None):
    contact = self.get_object(pk)
    serializer = ContactSerializer(contact)
    if format == 'json' or format == "api":
        return Response(serializer.data)
    else:
        return Response({'contact': contact, 'serializer':serializer}, template_name="contact/contact_detail.html")        

但是GET /contacts/1.json,1.api或1.html ALL给我正确的输出。因此,似乎我为默认的内容协商创建了一个问题,即format = None

But GET /contacts/1.json , 1.api, or 1.html ALL give me the correct output. So it seems that I have created an issue with the content negotiation for the default i.e. format=None

我必须缺少一些基本知识。我已经阅读了2个教程,并阅读了 Renderers 文档,但我不清楚我在这里的默认设置。我没有在settings.py中使用DEFAULT_RENDERERS,似乎在默认情况下还是在上面显示的实际类中都没有影响。

I must be missing something fundamental. I have gone through the 2 tutorials and read the Renderers docs but I am unclear on what I messed up here as far as the default. I am NOT using the DEFAULT_RENDERERS in settings.py, didn't seem to make a difference if in default or inside the actual class as shown above.

如果有人知道,不用打开格式值就可以使用TemplateHTMLRenderer的一种方法,我非常高兴。

Also if anyone knows a way to use TemplateHTMLRenderer without needing to switch on format value, I'm all ears.

编辑:如果我使用

if format == 'json' or format == "api" or format == None:
    return Response(serializer.data)
else:
    return Response({'contact': contact, 'serializer':serializer},

然后默认情况下,我会看到可浏览的API。不幸的是,我想要的是Template HTML视图,默认情况下设置为向最终用户显示表单。我想为开发人员保留.api格式。

Then I am shown the browsable API by default. Unfortunately, what I want is the Template HTML view by default, which is set to show forms for end users. I would like to keep the .api format for developers.

推荐答案

TL;博士:检查渲染器的顺序-尝试按照声明的顺序进行尝试,直到内容协商匹配或发生错误为止。

更改行

renderer_classes = (BrowsableAPIRenderer, JSONRenderer, TemplateHTMLRenderer, )

renderer_classes = (TemplateHTMLRenderer, BrowsableAPIRenderer, JSONRenderer, )

为我工作。我相信原因是因为在尝试查找渲染器时,内容协商程序从渲染器类元组中的第一个元素开始。当我有 format == None 时,我认为DRF可以继续进行,因此假设我的意思是默认,这似乎是第一个

Worked for me. I believe the reason is because the content negotiator starts at the first element in the renderer classes tuple when trying to find a renderer. When I have format==None, I'm thinking there is nothing else for DRF to go on, so it assumes I mean the "default" which seems to be the first in the tuple.

编辑:因此,正如@Ross在他的回答中指出的那样,项目的settings.py中也有一个全局设置。如果我删除类级别 renderer_classes 声明,而在settings.py

So, as pointed out by @Ross in his answer, there is also a global setting in the settings.py for the project. If I remove my class level renderer_classes declaration and instead use this in settings.py

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

然后我得到一个(不同)JSON错误。但是,只要
'rest_framework.renderers.BrowsableAPIRenderer',就不会首先列出
,例如:

Then I get a (different) JSON error. However, as long as 'rest_framework.renderers.BrowsableAPIRenderer', is not listed first, for example:

 # SUCCESS, even though JSON renderer is checked first
'DEFAULT_RENDERER_CLASSES': (
    'rest_framework.renderers.JSONRenderer',        
    'rest_framework.renderers.TemplateHTMLRenderer',
    'rest_framework.renderers.BrowsableAPIRenderer',
)

所以如果我们点击BrowsableAPIRenderer在尝试使用TemplateHTMLRenderer之前,我们会收到一个错误-无论我们是依靠renderer_classes还是DEFAULT_RENDERER_CLASSES 。我想它会优雅地通过JSONRenderer,但是无论出于何种原因BrowsableAPIRenderer都会引发异常。

So if we hit BrowsableAPIRenderer before we try TemplateHTMLRenderer then we get an error - whether or not we are relying on renderer_classes or DEFAULT_RENDERER_CLASSES. I imagine it passes through JSONRenderer gracefully but for whatever reason BrowsableAPIRenderer raises an exception.

因此,在分析了此内容之后,我简化了视图代码。

So I have simplified my view code after analyzing this...

def get(self, request, pk, format=None):
        contact = self.get_object(pk)
        serializer = ContactSerializer(contact)
        if format == None:
            return Response({'contact': contact, 'serializer':serializer}, template_name="contact/contact_detail.html")        
        else:
            return Response(serializer.data)

..这更好地反映了我本来的样子试图做任何事情。

..which better reflects what I was originally trying to do anyway.

这篇关于Django Rest Framework:我的默认渲染器发生了什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆