如何更新单行上的单列?

How to update a single column on a single row?

我正在尝试为我的 Django REST 应用程序编写一个简单的更新视图,但我不知道该怎么做。我收到了从 403 到 500 的一系列错误。

基本上,我有一个 table 'Foo',我想将 'active' 字段从 'True' 设置为 'False'。这是我目前的观点:

class DisableFoo(generics.UpdateAPIView):
    permission_classes = (permissions.IsAuthenticated,)
    serializer_class = FooSerializer
    queryset = Foo.objects.all()

    def perform_update(self, serializer):
        queryset = Foo.objects.filter(pk = self.request.data['id'])
        queryset.update(active = False)

但是,这会导致 AssertionError:

Expected view DisableFoo to be called with a URL keyword argument named "pk".
Fix your URL conf, or set the '.lookup_field' attribute on the view correctly.

您不应发送要更新的行的 id request.data,而应在 url.

内发送

所以如果你现在正在打类似这样的东西:

/api/foo/

试试

/api/foo/<id>/

当然这还不够。你还应该考虑更多的事情。

您正在使用 perform_update 方法。但这不太可能是正确的。调用 perform_update 是为了用 serializer.save() 更新整个对象,因此它仅在 serializer.is_valid() 时被调用。

这意味着您必须发送有效的 Foo 对象。但这不是你想要的。您只需要更新 Foo 对象的单个字段。所以这里正确的做法是使用partial_updatepartial_update 将在您向 /api/foo/<id>/

发出 PATCH 请求时使用

因此,如果您向 /api/foo/<id>/ 发送 PATCH 请求并在 request.data 中发送 active=0,DRF 将自动更新对象,而无需进一步更改代码。只需使用

class DisableFoo(generics.UpdateAPIView):
    permission_classes = (permissions.IsAuthenticated,)
    serializer_class = FooSerializer
    queryset = Foo.objects.all()

但这最终会公开您所有的模型字段以进行更新。所以你可以像这样覆盖 partial_update 方法:

def partial_update(self, request, *args, **kwargs):
    instance = self.get_object()
    instance.active = False
    instance.save(update_fields=['active'])
    return Response()

另一种方法

DRF 支持通过 @detail_route@list_route 装饰器创建 extra extra-actions

您可以使用 @detail_route 创建自定义禁用操作。考虑以下代码和平:

class FooViewSet(viewsets.GenericViewSet):
    queryset = Foo.objects.all()
    serializer_class = FooSerializer

    @detail_route(methods=['post'])
    def disable(self, request, pk=None):
        instance = self.get_object()
        instance.active = False
        instance.save(update_fields=['active'])
        return Response('done')

/api/foo/<id>/disable发出POST请求将调用我们刚刚编写的disable方法并禁用<id>下的foo实例。

这样您就可以避免使用 PATCH 请求方法的要求。