【问题标题】:Django DRF add request.user to modelserializerDjango DRF 将 request.user 添加到模型序列化器
【发布时间】:2019-08-28 05:09:19
【问题描述】:

我正在使用 django rest 框架,并且我有一个通过模型视图集和模型序列化器创建的对象。此视图只能由经过身份验证的用户访问,并且对象应将其“uploaded_by”字段设置为该用户。

我已阅读文档,并得出结论认为这应该有效

视图集:

class FooViewset(viewsets.ModelViewSet):
    permission_classes = [permissions.IsAdminUser]
    queryset = Foo.objects.all()
    serializer_class = FooSerializer

    def get_serializer_context(self):
        return {"request": self.request}

序列化器:

class FooSerializer(serializers.ModelSerializer):
    uploaded_by = serializers.PrimaryKeyRelatedField(
        read_only=True, default=serializers.CurrentUserDefault()
    )

    class Meta:
        model = Foo
        fields = "__all__"

但是,这会导致以下错误:

django.db.utils.IntegrityError: NOT NULL constraint failed: bar_foo.uploaded_by_id

这表明“uploaded_by”没有被序列化程序填充。

根据我对文档的理解,这应该已将该字段添加到来自序列化程序的已验证数据中,作为 create 方法的一部分。

显然我误解了什么!

【问题讨论】:

    标签: django django-rest-framework django-serializer django-rest-viewsets


    【解决方案1】:

    问题在于uploaded_by 字段的read_only 属性:

    API 输出中包含只读字段,但不应包含 在创建或更新操作期间包含在输入中。任何 序列化程序中错误包含的“read_only”字段 输入将被忽略。

    将此设置为 True 以确保在序列化一个 表示,但在创建或更新实例时不使用 在反序列化期间。

    Source

    基本上它用于显示对象的表示,但在任何更新和创建过程中都被排除在外。

    相反,您可以通过手动分配覆盖create 函数来存储所需的用户。

    class FooSerializer(serializers.ModelSerializer):
    
        uploaded_by = serializers.PrimaryKeyRelatedField(read_only=True)
    
        def create(self, validated_data):
            foo = Foo.objects.create(
                uploaded_by=self.context['request'].user,
                **validated_data
            )
            return foo
    

    【讨论】:

    • 啊,有道理,但是没有 read_only 就不行:AssertionError: Relational field must provide a queryset argument, override get_queryset, or set read_only=True.跨度>
    • HiddenField 似乎在创建方面有效,但序列化程序在显示已存在的对象时不显示 upload_by 字段
    • 好吧,本质上是一个序列化器用于序列化输入数据,如果你想填充某些字段,你可以在 perform_create 函数中完成。我已经更新了我的答案并删除了 HiddenField 部分,因为我不知道您也想展示 uploaded_by 字段
    • 文档说 perform_create 应该在视图集中,但我在两个都试过了,从来没有调用过
    • 我明白了,您是否尝试将source='user.id'(或只是source='user')作为attribute 添加到原始PrimaryKeyRelatedField ?在我当前的答案中不使用我提出的任何解决方案。
    【解决方案2】:

    更干净的方式:

    class PostCreateAPIView(CreateAPIView, GenericAPIView):
        queryset = Post.objects.all()
        serializer_class = PostCreationSerializer
    
        def perform_create(self, serializer):
            return serializer.save(author=self.request.user)
    
    class PostCreationSerializer(serializers.ModelSerializer):
        author = serializers.PrimaryKeyRelatedField(read_only=True)
    
        class Meta:
            model = Post
            fields = ("content", "author")
    

    【讨论】:

      【解决方案3】:

      DRF 教程 recommend 在这种情况下覆盖 perform_create 方法,然后编辑 serializer 使其反映到新字段

      from rest_framework import generics, serializers
      from .models import Post
      
      
      class PostSerializer(serializers.HyperlinkedModelSerializer):
          author = serializers.ReadOnlyField(source='author.username')
      
          class Meta:
              model = models.Post
              fields = ['title', 'content', 'author']
      
      
      class ListPost(generics.ListCreateAPIView):
          queryset = Post.objects.all()
          serializer_class = PostSerializer
      
          def perform_create(self, serializer):
              return serializer.save(author=self.request.user)
      

      【讨论】:

      • 在使用作者字段保存之前检查序列化程序是否有效,例如serializer.is_valid()
      猜你喜欢
      • 2018-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-26
      • 2015-03-12
      • 1970-01-01
      • 2020-05-23
      相关资源
      最近更新 更多