Как создать/обновить/получить несколько моделей в одном представлении в Django Rest Framework

У меня есть бизнес-модель и модель заказов. Бизнесмены могут заказывать мебель на нашем сайте. Пользователь создает учетную запись и делает заказ. Поскольку он новый пользователь, он не связан ни с каким бизнесом. В форме заказа он укажет информацию о своем бизнесе и некоторую информацию, связанную с текущим заказом. Будет создана новая запись "Бизнес" и запись "Заказ" с указанной информацией. Существует внешний ключ для Business в таблице Order.

Если он захочет создать второй заказ, поскольку у него уже есть бизнес, в его форме будет предварительно заполнена информация о бизнесе. Когда он введет данные заказа и отправит его, бэкенд не будет создавать новую запись о бизнесе. Он только создаст запись о заказе и сохранит ссылку на бизнес.

Как мне достичь этого в одной конечной точке для создания обновления и получения?

Вот как будет выглядеть мой запрос

{
    
    "chairs": 3,
    "tables": 1,
    "delivery_type": "ONE_DAY",
    "payment_type": "CASH_ON_DELIVERY",
    "business": {
        "name": "Vin.AI",
        "website": "https://lol.com",
        "address": "My street",
        "city": "Gotham City",
        "state": "New York",
        "country": "USA",
    }
}

Вот какой ответ я получаю

{
    "business": [
        "Incorrect type. Expected pk value, received dict."
    ]
}

Проблема проста. Ваш сериализатор ожидает поле business как PK, а не как dict, как вы отправляете в своей полезной нагрузке. Тем не менее, чтобы выполнить требуемое действие, необходимо проделать некоторую работу. Кроме того, модели также немного странные, но я не буду углубляться в этот вопрос.

В настоящее время модель Business не имеет поля, которое могло бы связать с ней User. Это означает, что вы будете знать, кто создал Order, но никогда не узнаете, кто создал Business.

Основываясь на том, что вы сказали, я предполагаю, что Business принадлежит User и только одному. (Конечно, вы можете легко изменить это с помощью отношения "один-ко-многим").

Итак, начиная с небольшой модификации ваших моделей, удалите applicant из Order и добавьте в Business (владелец, я полагаю):

class Business(models.Model):
    applicant = models.OneToOneField(
        User,
        on_delete=models.DO_NOTHING,
        primary_key=True
    )
    ...

Кроме того, есть небольшая ошибка в BusinessSerializer, нет поля с названием status, удалите строку:

class BusinessSerializer(serializers.ModelSerializer):
    class Meta:
        ...

    def create(self, validated_data):
        ...
        # validated_data["status"] = "CREATED"
        return super().create(validated_data)

Существует более одного подхода к решению этой проблемы. Но если говорить просто:

  1. Проверяем, есть ли в текущем User текущий Business
  2. .
  3. Если нет, то создаем его, учитывая данные полезной нагрузки
class BusinessOrderAPIView(generics.CreateAPIView):
    permission_classes = [permissions.IsAuthenticated]
    queryset = Order.objects.all()
    serializer_class = OrderSerializer
    business_serializer = BusinessSerializer

    def create(self, request, *args, **kwargs):
        user_business = None
        try:
            user_business = request.user.business

        except ObjectDoesNotExist:
            business = request.data.pop("business")
            business["applicant"] = request.user.pk
            business_serializer = self.business_serializer(data=business)
            business_serializer.is_valid(raise_exception=True)
            user_business = business_serializer.save()

        request.data["business"] = user_business.pk
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(
            serializer.data, status=status.HTTP_201_CREATED, headers=headers
        )

Вы можете адаптировать этот код в нескольких формах. В случае если вы хотите сохранить оригинальный формат, просто используйте try/except для запроса Business, заданного каким-либо уникальным идентификатором (например, name или website).

Вернуться на верх