Django Rest Framework更新字段

47

我刚开始接触DRF,正在尝试编写自定义视图/序列化程序,以便只更新用户对象的一个字段。

我需要编写逻辑来仅更新用户的“名称”。

我已经编写了序列化器:

class ClientNameSerializer(serializers.ModelSerializer):
    class Meta:
        model = ClientUser
        fields = ('name',)

    def update(self, instance, validated_data):
        instance.name = validated_data.get('name', instance.name)
        instance.save()
        return instance

这个方法从未被调用。我尝试在那里设置断点并进行调试,但它从未被调用,即使我使用PUT、POST或PATCH方法。如果我添加create方法,当我使用POST时它会被调用。

这是我的视图的样子:

class UpdateName(generics.CreateAPIView):
    queryset = ClientUser.objects.all()
    serializer_class = ClientNameSerializer
    permission_classes = (permissions.IsAuthenticated,)

有人有什么建议吗?谢谢!

我的 models.py 看起来是这样的

class ClientUser(models.Model):
    owner = models.OneToOneField(User,unique=True,primary_key=True)

    phone_number = models.CharField(validators=[PHONE_REGEX],max_length=20,unique=True)

    name = models.CharField(max_length=100,blank=True)
    status = models.IntegerField(default=1)
    member_from = models.DateTimeField('member from',auto_now_add=True)
    is_member = models.BooleanField(default=False)
3个回答

44

端点可以接受哪些方法的定义是在视图中完成的,而不是在序列化器中完成的。

你在序列化器下面的更新方法需要移动到视图中,这样你就会有类似于:

serializers.py

class ClientNameSerializer(serializers.ModelSerializer):
    class Meta:
        model = ClientUser

views.py

class UpdateName(generics.UpdateAPIView):
    queryset = ClientUser.objects.all()
    serializer_class = ClientNameSerializer
    permission_classes = (permissions.IsAuthenticated,)

    def update(self, request, *args, **kwargs):
        instance = self.get_object()
        instance.name = request.data.get("name")
        instance.save()

        serializer = self.get_serializer(instance)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        return Response(serializer.data)

请注意,您正在覆盖UpdateModelMixin,您可能需要稍微更改上面的代码以使其正确。


嗨,更新方法在此行中断:instance = self.get_object() - Bob
1
这是我收到的错误信息:期望调用名为“pk”的URL关键字参数的视图UpdateName。修复您的URL配置,或正确设置视图上的.lookup_field属性 - Bob
@bla0009,你是怎么解决这个问题的?URL 关键字参数 pk 是什么? - momokjaaaaa
1
@momokjaaaaa 更新某个属性的最佳方式实际上是使用queryset,因此您可以编写例如Person.objects.filter(....).update(name="some name") - Bob
1
在视图内重写 update 方法和在序列化器内重写 update 方法有何不同? - Karesh A
显示剩余2条评论

6

另一种方法可能是以下方式:

serializer.py

class ClientNameSerializer(serializers.ModelSerializer):
   class Meta:
        model = ClientUser
        fields = ('name',)

   def update(self, instance, validated_data): 
        instance.name = validated_data.get('name', instance.name)
        instance.save()
        return instance

views.py

class UpdateName(generics.UpdateAPIView):
    queryset = ClientUser.objects.all()
    serializer_class = ClientNameSerializer
    permission_classes = (permissions.IsAuthenticated,)

    def update(self, request, *args, **kwargs):
        data_to_change = {'name': request.data.get("name")}
        # Partial update of the data
        serializer = self.serializer_class(request.user, data=data_to_change, partial=True)
        if serializer.is_valid():
            self.perform_update(serializer)

        return Response(serializer.data)

5
如果您使用class UpdateName(generics.CreateAPIView),那么这只会在序列化器上调用create()方法。
相反,您应该子类化generics.UpdateAPIView。就是这样。 您不必将方法移动到视图中,如此答案建议的那样(它基本上是复制/重复UpdateModelMixin的更新方法)
有关序列化器如何处理保存/更新的更多信息,请参见此处的文档:

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接