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

时间:2016-05-17 11:47:57

标签: django-rest-framework

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

StackOverflow上的几个问题(12)建议我覆盖get_serializer_context()的{​​{1}}方法。我做了,但没有帮助。我试图理解,有什么不对,并且发现我不能从源代码中理解这个上下文系统应该如何工作。 (关于此事的文件也缺失了)

有人可以解释一下,序列化程序在正常请求数据中添加了上下文吗?我找到了两个地方,它从上下文中保存了值。

  1. serializer.save(),方法,将kwargs与验证数据混合,但通常不带参数调用(例如ModelMixins)。
  2. fields.__new__(),它缓存args和kwargs,但似乎以后没有人读过它们。

2 个答案:

答案 0 :(得分:11)

每当您使用通用视图或视图集时,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
        }

答案 1 :(得分:0)

  

设置不是通过request.data设置的字段值,而是通过url参数或cookie中的值设置。例如,我需要在POST请求时将我的Comment模型的用户字段设置为等于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的标准对象,但除了这一点之外。 :)