Django Rest Framework - 从 ModelViewSet 中覆盖的 .create() 方法调用 .update()
Django Rest Framework - Calling .update() from an overriden .create() method inside ModelViewSet
我正在使用 Django 2.2.x 和 djangorestframework 3.11.1.
在 ModelViewSet 中,我必须重写 .create() 方法来自定义默认行为。
有时我需要在收到 POST http 请求后真正创建一个新模型实例,有时我需要 .update() 一个现有实例,但我只能收到 POST 请求(来源是我无法控制的外部服务器)。我知道将创建和更新混为一谈是个坏主意...
问题是每当我的更新而不是创建逻辑启动时,我都会收到以下错误:
AssertionError: Expected view EventViewSet to be called with a URL keyword argument named "pk". Fix your URL conf, or set the `.lookup_field` attribute on the view correctly
我尝试了另外两种方法来解决这个问题:
- 直接调用
Event.objects.update()
但我意识到这对我来说是行不通的,因为我覆盖了 get_serializer()
方法来改变来自外部服务器的原始 json 有效载荷并且我不想在这里重复自定义逻辑。
- 调用了django内置的
.update_or_create()
方法,但是过滤有点太复杂了,还是和第一弹一样的问题
我的看法:
class EventViewSet(LoggingMixin, viewsets.ModelViewSet):
"""this is our main api. It allows an event to be created, retrieved, updated and
deleted
"""
def create(self, request, *args, **kwargs):
# first off, we need to find if there is one event NOT closed for the same
# customer, device name and ip address
filters = Q(customer = request.data["Customer"]) & \
~Q(status = "CLOSED") & \
Q(device_name = request.data["DisplayName"]) & \
Q(ip_address = request.data["Address"])
query_set = Event.objects.filter(filters)
if len(query_set) == 1:
# it means there is already an event still NOT closed for that customer/device,
# so we update the existing event
# we need to specify which event we are updating
kwargs["pk"] = str(query_set[0].pk)
return super().update(request, *args, **kwargs)
elif len(query_set) == 0:
# it means there is no open event for that customer/device, hence we need to create it
return super().create(request, *args, **kwargs)
# per our business logic, we should never be here, because there should never be more
# than 1 *open* event for the same customer/device.
else:
pass
我不确定如何修复返回的 AssertionError
。
谢谢
找到解决方案。
我非常接近...我缺少的是:
self.kwargs["pk"] = str(query_set[0].pk)
而不是kwargs["pk"] = str(query_set[0].pk)
据我了解,这条信息然后在 ModelViewSet get_object()
方法中用于检索要更新的实际实例。
我正在使用 Django 2.2.x 和 djangorestframework 3.11.1.
在 ModelViewSet 中,我必须重写 .create() 方法来自定义默认行为。
有时我需要在收到 POST http 请求后真正创建一个新模型实例,有时我需要 .update() 一个现有实例,但我只能收到 POST 请求(来源是我无法控制的外部服务器)。我知道将创建和更新混为一谈是个坏主意...
问题是每当我的更新而不是创建逻辑启动时,我都会收到以下错误:
AssertionError: Expected view EventViewSet to be called with a URL keyword argument named "pk". Fix your URL conf, or set the `.lookup_field` attribute on the view correctly
我尝试了另外两种方法来解决这个问题:
- 直接调用
Event.objects.update()
但我意识到这对我来说是行不通的,因为我覆盖了get_serializer()
方法来改变来自外部服务器的原始 json 有效载荷并且我不想在这里重复自定义逻辑。 - 调用了django内置的
.update_or_create()
方法,但是过滤有点太复杂了,还是和第一弹一样的问题
我的看法:
class EventViewSet(LoggingMixin, viewsets.ModelViewSet):
"""this is our main api. It allows an event to be created, retrieved, updated and
deleted
"""
def create(self, request, *args, **kwargs):
# first off, we need to find if there is one event NOT closed for the same
# customer, device name and ip address
filters = Q(customer = request.data["Customer"]) & \
~Q(status = "CLOSED") & \
Q(device_name = request.data["DisplayName"]) & \
Q(ip_address = request.data["Address"])
query_set = Event.objects.filter(filters)
if len(query_set) == 1:
# it means there is already an event still NOT closed for that customer/device,
# so we update the existing event
# we need to specify which event we are updating
kwargs["pk"] = str(query_set[0].pk)
return super().update(request, *args, **kwargs)
elif len(query_set) == 0:
# it means there is no open event for that customer/device, hence we need to create it
return super().create(request, *args, **kwargs)
# per our business logic, we should never be here, because there should never be more
# than 1 *open* event for the same customer/device.
else:
pass
我不确定如何修复返回的 AssertionError
。
谢谢
找到解决方案。
我非常接近...我缺少的是:
self.kwargs["pk"] = str(query_set[0].pk)
而不是kwargs["pk"] = str(query_set[0].pk)
据我了解,这条信息然后在 ModelViewSet get_object()
方法中用于检索要更新的实际实例。