Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Json Django Rest框架:我的默认渲染器怎么了?_Json_Django_Django Rest Framework - Fatal编程技术网

Json Django Rest框架:我的默认渲染器怎么了?

Json Django Rest框架:我的默认渲染器怎么了?,json,django,django-rest-framework,Json,Django,Django Rest Framework,我希望调用/contacts/1.json返回json,调用1.api返回browsableAPI,调用format=None aka/contacts/1/返回一个我们称之为render_form的模板。这样最终用户可以拥有漂亮的表单,开发人员可以使用.api格式,ajax/apps等可以使用.json。似乎是一个常见的用例,但在DRF中有些东西不适合我 在没有给定格式的情况下,DRF如何确定所使用的渲染器。我在stack exchange上找到并丢失了一些信息,基本上是说根据格式分割响应。添

我希望调用/contacts/1.json返回json,调用1.api返回browsableAPI,调用format=None aka/contacts/1/返回一个我们称之为render_form的模板。这样最终用户可以拥有漂亮的表单,开发人员可以使用.api格式,ajax/apps等可以使用.json。似乎是一个常见的用例,但在DRF中有些东西不适合我

在没有给定格式的情况下,DRF如何确定所使用的渲染器。我在stack exchange上找到并丢失了一些信息,基本上是说根据格式分割响应。添加TemplateHTMLRenderer引起了各种各样的痛苦。我曾尝试根据格式进行拆分,但这给了我下面的JSON错误

我不理解定义应该使用什么渲染器的实际方式。特别是当没有提供格式时。我的意思是,当使用响应(数据)时,它“只起作用”。我可以让TemplateHTMLRenderer工作,但代价是没有默认的渲染器

GET/contacts/1/给出错误:
不是JSON可序列化的

使用此代码:

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都提供了正确的输出。因此,我似乎为默认设置的内容协商创建了一个问题,即format=None

我一定错过了一些基本的东西。我已经阅读了2个文档,但我不清楚我在这里搞砸了什么,因为默认情况。我没有在settings.py中使用默认的_渲染器,在默认情况下或在实际类中似乎没有什么区别,如上所示

另外,如果有人知道一种不用打开格式值就可以使用TemplateHTMLRenderer的方法,我洗耳恭听

编辑:如果我使用

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

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

当我查看源代码时,优先级似乎是settings.py中
DEFAULT\u RENDERER\u CLASSES
参数中指定的渲染器顺序:

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.TemplateHTMLRenderer',
    ),
    'DEFAULT_PARSER_CLASSES': (
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.TemplateHTMLRenderer',
    )
}

因此,如果您指定一组渲染器类,那么将根据
.json/.api/.html
扩展名和
Accept:
标题(而不是
内容类型
,正如我在对您的问题的评论中所说的)是否对请求有效来选择第一个有效的渲染器;DR:检查渲染器的顺序-按照声明的顺序尝试渲染器,直到内容协商匹配或出现错误。

换线

renderer_classes = (BrowsableAPIRenderer, JSONRenderer, TemplateHTMLRenderer, )

为我工作。我相信这是因为内容协商者在试图查找渲染器时从renderer classes元组的第一个元素开始。当我有
format==None
时,我认为DRF没有其他功能,所以它假设我指的是“default”,它似乎是元组中的第一个

编辑:所以,正如@Ross在他的回答中指出的,在settings.py中还有一个全局设置用于项目。如果我删除我的类级别
renderer\u类
声明并在settings.py中使用它

# ERROR
REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (    
        'rest_framework.renderers.BrowsableAPIRenderer',
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.TemplateHTMLRenderer',
    )
}
然后我得到一个(不同的)JSON错误。但是只要 “rest_framework.Renders.BrowsableapInderer”, 未首先列出,例如:

 # SUCCESS, even though JSON renderer is checked first
'DEFAULT_RENDERER_CLASSES': (
    'rest_framework.renderers.JSONRenderer',        
    'rest_framework.renderers.TemplateHTMLRenderer',
    'rest_framework.renderers.BrowsableAPIRenderer',
)
因此,如果在尝试TemplateHTMLRenderer之前点击BrowsableapInderer,则会出现错误-无论我们是否依赖渲染器类还是默认渲染器类。我想它会优雅地通过JSONRenderer,但不管出于什么原因,BrowsableapInderer都会引发一个异常

所以在分析了这个之后,我简化了我的视图代码

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)

…这更好地反映了我本来想做的事

内容类型
是次要决定因素。请从您的链接中查看@Ross Rogers:“REST框架使用一种简单的内容协商方式,根据可用的呈现器、每个呈现器的优先级以及客户端的Accept:header来确定应将哪种媒体类型返回给客户端。”在这种情况下,我想我是在询问呈现器的优先级。请原谅我,如果我很密集,但我不确定
内容类型
是如何发挥作用的。也许你的意思是以.json结尾的url?你必须为每个视图添加该字段。如果您设置默认值,那不是更容易吗?只要大多数视图类需要这样做,您是对的,但大多数视图类可能不会这样做。我昨天的出发点是:除了联系人之外,其他一切都是我想要的,我如何在联系人的组合中得到一个简单的表单?不管是哪种方式,问题都归结为在尝试TemplateHtmlRenderer之前将数据传递给BrowsableapInderer感谢您的深入研究,我同意“优先级似乎是在settings.py中的DEFAULT_RENDERER_CLASSES参数中指定的渲染器的顺序”。正如您所回答的,我用不同的方式解决了这个问题,重新排序了渲染器类。顺便说一句,出于我的目的,默认的解析器类不需要声明。我可以用你的方法,或者你的类方法来实现它。太好了!我同意这两种方法都有效。但是,在
DEFAULT\u RENDERER\u类中执行此操作将在一个位置执行。否则,您必须在每个APIView中设置
renderer\u类。不管怎样,很高兴你跨越了障碍。
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)