Django:使用 GET 而不是 PATCH 更新特定字段

Ste*_*evy 5 python django django-rest-framework

语境

对于特定用例,我需要能够Visitor使用 GET 请求而不是 PATCH 请求更新模型的单个字段。

我的相关访客模型如下所示:

# models.py

class Visitor(models.Model):
    visitor_uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, db_index=True)
    customers = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name='customer_visitors')
    audiences = models.ManyToManyField(Audience, related_name='audience_visitors')
    cid = models.CharField(max_length=255, unique=True)
    uid = models.CharField(max_length=255)
    cup = JSONField(null=True)

    def __str__(self):
        return self.cid

    class Meta:
        db_table = 'visitor'
Run Code Online (Sandbox Code Playgroud)

我正在使用这样一个简单的序列化程序:

# serializers.py

class VisitorSerializer(serializers.ModelSerializer):
    class Meta:
        model = Visitor
        fields = ('customers', 'cid', 'uid', 'cup')
Run Code Online (Sandbox Code Playgroud)

我可以只更新cup特定字段的字段,该字段Visitor是使用cid带有 PATCH的唯一字段查找的,如下所示:

# views.py

class VisitorViewSet(viewsets.ModelViewSet):
    serializer_class = VisitorSerializer
    queryset = Visitor.objects.all()
    lookup_field = 'cid'

    def list(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.serializer_class(instance, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data)
Run Code Online (Sandbox Code Playgroud)

问题

问题是我无法使用 GET 请求cup根据给定的唯一cid字段更新访问者的字段。

我试过的

正如Uri Shalit 的这个答案所建议的那样,我尝试get_serializer()在我的内部覆盖VisitorViewSet并尝试list()像这样使用它:

# views.py

class VisitorViewSet(viewsets.ModelViewSet):
    serializer_class = VisitorSerializer
    queryset = Visitor.objects.all()
    lookup_field = 'cid'

    def get_serializer(self, *args, **kwargs):
        kwargs['partial'] = True
        return super(VisitorViewSet, self).get_serializer(*args, **kwargs)

    def list(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data)
Run Code Online (Sandbox Code Playgroud)

但是,仅根据cup字段更新特定访问者的cid字段适用于 PATCH 请求,但不会使用 GET 请求更新所述字段。也没有错误。

预期行为

发出 GET 请求,其中包含cid识别访问者以及cup需要为给定访问者更新的数据。我知道它违反了 REST 原则,但对于这个用例,我需要使用 GET 请求而不是 PATCH 请求来执行此部分更新。

任何正确方向的帮助或指示将不胜感激!

Oha*_*Lad 2

在您的模型中添加一个类方法。

class Visitor(models.Model):
    visitor_uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, db_index=True)
    customers = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name='customer_visitors')
    audiences = models.ManyToManyField(Audience, related_name='audience_visitors')
    cid = models.CharField(max_length=255, unique=True)
    uid = models.CharField(max_length=255)
    cup = JSONField(null=True)

    def __str__(self):
        return self.cid

    class Meta:
        db_table = 'visitor'


    @classmethod
    def update_cup(cls, cid, cup_new):
        instance = cls.objects.get(cid=cid)
        instance.cup = new_cup
        instance.save()
Run Code Online (Sandbox Code Playgroud)

在ModelViewSet中重写该get_queryset方法,如下:

我不知道你如何计算 new_cup 我猜你把它作为查询参数

def get_queryset(self):
    queryset = Visitor.objects.all()

    cup_new = self.request.query_params.get('cup_new', None)
    cid = self.request.query_params.get('cid', None)

    [obj.update_cup(obj.cid, cup_new) for obj in queryset if obj.cid == cid]
    return queryset
Run Code Online (Sandbox Code Playgroud)