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

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

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

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

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

【问题讨论】:

    标签: django-rest-framework


    【解决方案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/…
      最近更新 更多