Django REST Framework:序列化程序上下文如何工作?

Posted

技术标签:

【中文标题】Django REST Framework:序列化程序上下文如何工作?【英文标题】:Django REST Framework: how serializer context works? 【发布时间】:2016-09-13 12:04:45 【问题描述】:

在 Django REST 框架中,提供额外的 args/kwargs 以设置不是通过 request.data 设置的字段值,而是通过 url 参数或 cookie 中的值,这是 Django REST 框架中的一项非常标准的任务。例如,我需要在 POST 请求时将我的 Comment 模型的 user 字段设置为等于 request.user。这些额外的参数称为上下文。

*** 上的几个问题(1、2)建议我覆盖我的ModelViewSetget_serializer_context() 方法。我做到了,但没有帮助。我试图理解,出了什么问题,并从源代码中发现我不明白这个上下文系统应该如何工作。 (也缺少有关此问题的文档)

谁能解释一下,序列化程序在哪里将上下文添加到正常的请求数据中?我找到了两个地方,它保存了上下文中的值。

    serializer.save(),方法,将 kwargs 与经过验证的数据混合在一起,但通常在没有参数的情况下调用它(例如,ModelMixins)。 fields.__new__(),它缓存了 args 和 kwargs,但似乎没有人以后再阅读它们。

【问题讨论】:

【参考方案1】:

设置字段的值不是通过 request.data 设置的,而是通过 url 参数或 cookie 中的值。例如,我需要在 POST 请求时将我的 Comment 模型的 user 字段设置为 request.user。

这就是我在 ModelViewSet 中处理这两种情况的方式:

def perform_create(self, serializer):

    # Get article id from url e.g. http://myhost/article/1/comments/
    # obviously assumes urls.py is setup right etc etc
    article_pk = self.kwargs['article_pk']
    article = get_object_or_404(Article.objects.all(), pk=article_pk)

    # Get user from request
    serializer.save(author=self.request.user, article=article)

不幸的是,嵌套对象不是 DRF 的标准,但这不是重点。 :)

【讨论】:

【参考方案2】:

每当您使用通用视图或视图集时,DRF(3.3.2) 都会将request 对象、view 对象和format 添加到序列化程序context。您可以使用serializer.context 进行访问,比如在序列化程序中使用request.user

这是在调用get_serializer_class() 时添加的。在其中,它调用get_serializer_context() 方法,将所有这些参数添加到其上下文中。

DRF源代码供参考:

class GenericAPIView(views.APIView):
    """
    Base class for all other generic views.
    """

    def get_serializer(self, *args, **kwargs):
        """
        Return the serializer instance that should be used for validating and
        deserializing input, and for serializing output.
        """
        serializer_class = self.get_serializer_class()
        kwargs['context'] = self.get_serializer_context()
        return serializer_class(*args, **kwargs)    

    def get_serializer_context(self):
        """
        Extra context provided to the serializer class.
        """
        return 
            'request': self.request,
            'format': self.format_kwarg,
            'view': self
        

【讨论】:

我想了这么多,但后来会发生什么?我看不出,Serializer 在哪里利用这个上下文来用取自它的值填充字段。 在正常情况下,序列化程序不会使用上下文。如果我们想在序列化程序中访问request 对象,我们将使用self.context.get('request')。此外,在任何序列化器字段的to_representation 方法中,我们可以使用self.context 变量访问context (来自docs)包含context 的一个常见情况是,如果您使用包含超链接关系的序列化程序,这要求序列化程序有权访问当前请求,以便它可以正确生成完全限定的 URL。 @Rahul Gupta 你能帮我看看这个吗? ***.com/questions/62039305/…

以上是关于Django REST Framework:序列化程序上下文如何工作?的主要内容,如果未能解决你的问题,请参考以下文章

python django-rest-framework 3.3.3 更新嵌套序列化程序

django-rest-framework、多表模型继承、ModelSerializers 和嵌套序列化器

Django.rest_framework:如何序列化一对多?

Django 序列化器与 rest_framework 序列化器

Django-Rest-Framework 中的序列化程序问题

django.core 序列化器和 Django Rest Framework 序列化器之间的区别