Django Rest Framework — вызов .update() из переопределенного метода .create() внутри ModelViewSet

Я использую Django 2.2.x и djangorestframework 3.11.1.

Внутри ModelViewSet мне пришлось переопределить метод .create(), чтобы настроить поведение по умолчанию.

Иногда мне нужно действительно создать новый экземпляр модели при получении http-запроса POST, иногда мне нужно .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, поступающую с внешнего сервера, и я не хочу дублировать здесь логику настройки.
  • вызов встроенного метода .update_or_create() django, но фильтрация была слишком сложной, и у меня все еще та же проблема с первой пулей

Мой взгляд:

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.

Спасибо


person pastoreerrante    schedule 29.11.2020    source источник


Ответы (1)


Нашел решение.

Я был очень близок... чего мне не хватало, так это:

self.kwargs["pk"] = str(query_set[0].pk)

вместо kwargs["pk"] = str(query_set[0].pk)

Насколько я понял, эта часть информации затем используется внутри метода ModelViewSet get_object() для извлечения фактического экземпляра для обновления.

person pastoreerrante    schedule 30.11.2020