【问题标题】:The proper way to set user ForeignKey value in DjangoRestFramework在 DjangoRestFramework 中设置用户 ForeignKey 值的正确方法
【发布时间】:2020-08-22 17:42:43
【问题描述】:

我有这个模型:

class Comment(models.Model):

    user = models.ForeignKey('users.User', on_delete=models.CASCADE, null=False)
    post = models.ForeignKey('posts.Post', on_delete=models.CASCADE, null=False)

    content = models.TextField(max_length=1000, null=False, blank=False)

    def __str__(self):
        """Return the comment str."""
        return "'{}'".format(self.content)

它的序列化器看起来像这样:

class CommentSerializer(serializers.ModelSerializer):

    class Meta:
        model = Comment
        fields = '__all__'

到目前为止,在检索数据方面做得很好,但是当我想 create 一个新的 Comment 时,这样做的正确方法是什么?

我的看法:

class CommentViewSet(viewsets.ModelViewSet):

    def get_permissions(self):
        permissions = []
        if self.action == 'create':
            permissions.append(IsAuthenticated)
        return [p() for p in permissions]

    def create(self, request):
        """Create a comment in some post."""

        serializer = CommentSerializer(data=request.data)
        if serializer.is_valid():  # False because user value is missing.
            serializer.save()
            return Response(serializer.data)
        else:
            return Response(serializer.errors)

没关系,我尝试覆盖 validate_user 并让它只是 pass,但是当我调用 is_valid 时验证仍在运行。我还尝试将request.user 附加到serializer.data,但它是不可变的。 如果我需要使用request.user,我怎么能做到这一点?我需要为序列化程序的该字段设置的值不在request.data 中。 (我认为让前端发送用户 ID 不是一个好主意)。

我想到的另一个解决方案是在serializer 中设置user 只读,然后在我调用save() 时将其添加到Django 对象中。但我想知道使用 DRF 更清洁、更安静的方法是什么。

【问题讨论】:

    标签: python django api rest django-rest-framework


    【解决方案1】:

    首先,您必须将 user 设置为 read_only 字段,这将关闭验证。

    class CommentSerializer(serializers.ModelSerializer):
        class Meta:
            model = Comment
            fields = '__all__'
            read_only_fields = ('user',)

    然后,覆盖视图集的perform_create(...)方法,

    class CommentViewSet(viewsets.ModelViewSet):
    
        def get_permissions(self):
            permissions = []
            if self.action == 'create':
                permissions.append(IsAuthenticated)
            return [p() for p in permissions]
    
        def perform_create(self, serializer):
            serializer.save(user=self.request.user)

    注意:
    您应该删除 viewsetcreate(...) 方法,因为它什么都不做“在您的情况下”

    【讨论】:

      【解决方案2】:

      您应该更改序列化程序以使用上下文并修补用户字段:

      class CommentSerializer(serializers.ModelSerializer):
          user = serializers.PrimaryKeyRelatedField(read_only=True)
      
          class Meta:
              model = Comment
              fields = '__all__'
      
          def create(self, validated_data):
              validated_data['user'] = self.context['request'].user
              return super().create(validated_data)

      CommentViewSet 中,不要覆盖create,因为create 函数更复杂,并且会为序列化程序提供上下文:

      class CommentViewSet(viewsets.ModelViewSet):
      
          def get_permissions(self):
              if self.action == 'create':
                  return [IsAuthenticated()]
              return []
      
          # no create

      【讨论】:

        【解决方案3】:

        models.py:

        class Comment(models.Model):
        
            user = models.ForeignKey('users.User', on_delete=models.CASCADE, null=False)
            post = models.ForeignKey('posts.Post', on_delete=models.CASCADE, null=False)
        
            content = models.TextField(max_length=1000, null=False, blank=False)
        
            def __str__(self):
                """Return the comment str."""
                return "'{}'".format(self.content)
           
            def get_username(self):
                return self.user.get_username()
        
            def get_post_title(self):
                return self.post.title
            
            # and so on ...
        
        

        serializers.py:

        class CommentSerializer(serializers.ModelSerializer):
            username = serializers.SerializerMethodField()
            post_title = serializers.SerializerMethodField()
            class Meta:
                model = Comment
                fields = [
                      "id", "username", "post_title", "content"
                  ]
            def get_username(self, obj):
                return obj.get_username()
        
            def get_post_title(self, obj):
                return obj.get_post_title()
        
        

        views.py:

        from rest_framework import generics
        from rest_framework.permissions import IsAuthenticated
        
        class CommentViewSet(generics.CreateAPIView):
            model = Comment
            queryset = Comment.objects.all()
            serializer_class = CommentSerializer
            permission_classes = [IsAuthenticated]
        

        【讨论】:

          猜你喜欢
          • 2022-12-31
          • 2018-06-05
          • 2019-09-28
          • 1970-01-01
          • 2020-09-03
          • 2019-05-11
          • 2013-09-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多