如何更新单行上的单列?
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_update
。 partial_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
请求方法的要求。
我正在尝试为我的 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_update
。 partial_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
请求方法的要求。