Как создать/обновить/получить несколько моделей в одном представлении в 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)
Существует более одного подхода к решению этой проблемы. Но если говорить просто:
- Проверяем, есть ли в текущем
User
текущийBusiness
.
- Если нет, то создаем его, учитывая данные полезной нагрузки
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
).