Задать вопрос
@NyxDeveloper

Как сохранять вложенные объекты ManyToMany в DjangoRestFramework?

Я хочу реализовать функцию добавления заказа в ресторане. У заказа есть два поля mtm, объекты которых создаются в момент создания заказа. Каким образом мне это сделать? Желательно одним запросом, в рамках одной транзакции.
Вот объект заказа:
#   заказ
class Order(models.Model):
    user = models.ForeignKey(UserProfile, verbose_name='Пользователь', on_delete=models.CASCADE, null=False)
    positions = models.ManyToManyField(OrderPosition, verbose_name='Позиции', related_name='order')
    address = models.CharField(verbose_name='Адресс доставки', blank=True, max_length=200)
    created = models.DateTimeField(verbose_name='Время создания заказа', default=timezone.now, null=False, blank=True)
    with_self = models.BooleanField(verbose_name='С собой', default=False)
    delivery_method = models.ForeignKey(DeliveryMethod, verbose_name='Способ доставки', on_delete=models.SET_NULL,
                                        null=True, blank=True)
    payment_method = models.ForeignKey(PaymentMethod, verbose_name='Способ оплаты', on_delete=models.SET_NULL,
                                       null=True, blank=True)
    processed = models.BooleanField(verbose_name='Заказ принят в обработку', default=True, blank=True)
    cook = models.BooleanField(verbose_name='Блюда готовятся', default=False, blank=True)
    deliver = models.BooleanField(verbose_name='Доставляется', default=False, blank=True)
    completed = models.BooleanField(verbose_name='Завершен', default=False, blank=True)


Вот объект позиции в заказе:
#   позиция в заказе
class OrderPosition(models.Model):
    position = models.ForeignKey(Position, on_delete=models.CASCADE)
    count = models.IntegerField(verbose_name='Количество в заказе', default=1)
    dishes = models.ManyToManyField(Dish, verbose_name='Выбранные блюда', related_name='dishes')
    toppings = models.ManyToManyField(Topping, verbose_name='Выбранные допинги', related_name='toppings', blank=True)


Вот их сериализаторы:
#   позиция в заказе
class OrderPositionRequestSerializer(serializers.ModelSerializer):
    class Meta:
        model = OrderPosition
        fields = '__all__'


#   заказ
class OrderRequestSerializer(serializers.ModelSerializer):
    position_set = OrderPositionRequestSerializer(many=True, read_only=True, source='positions')

    class Meta:
        model = Order
        fields = (
            'user',
            'address',
            'created',
            'with_self',
            'delivery_method',
            'payment_method',
            'processed',
            'cook',
            'deliver',
            'completed',
            'position_set'
        )


Слово "Request" в названии сериализатора означает, что им я сериализую тот json, который мне приходит от пользователя. Есть так же ResponseSerializers, которыми я сериализую собственные QuerySets перед отправкой пользователю. Выглядят они так:
class OrderPositionResponseSerializer(serializers.ModelSerializer):
    pos = PositionResponseSerializer(many=False, read_only=True, source='position')
    dish_set = DishResponseSerializer(many=True, read_only=True, source='dishes')
    topping_set = ToppingResponseSerializer(many=True, read_only=True, source='toppings')

    class Meta:
        model = OrderPosition
        fields = (
            'pos',
            'count',
            'dish_set',
            'topping_set'
        )


#   заказ
class OrderResponseSerializer(serializers.ModelSerializer):
    owner = UserProfileResponseSerializer(many=False, read_only=True, source='user')
    delivery = DeliveryMethodResponseSerializer(many=False, read_only=True, source='delivery_method')
    payment = PaymentMethodResponseSerializer(many=False, read_only=True, source='payment_method')
    position_set = OrderPositionResponseSerializer(many=True, read_only=True, source='positions')

    class Meta:
        model = Order
        fields = (
            'id',
            'owner',
            'position_set',
            'address',
            'created',
            'with_self',
            'delivery',
            'payment',
            'processed',
            'cook',
            'deliver',
            'completed'
        )


Помогите так же добрым советом, насколько хороша такая техника обработки запросов и ответов? Я до этого сам додумался, а значит в этом есть подвох (ЭТО ЗАКОН!)

Так выглядит моя вьюха:
#   заказы
class OrderView(APIView):
    def get(self, request):
        owner_id = request.data.get('owner_id')
        if owner_id:
            user = get_object_or_404(UserProfile.objects.all(), id=owner_id)
            if user.is_staff:
                orders = Order.objects.all()
            else:
                orders = Order.objects.filter(user__id=owner_id)
        else:
            return Response({'error': 'Укажите owner_id.'})
        serializer = OrderResponseSerializer(orders, many=True)
        return Response({'orders': serializer.data})

    def post(self, request):
        order = request.data.get('order')
        order_serializer = OrderRequestSerializer(data=order)
        if order_serializer.is_valid(raise_exception=True):
            order_saved = order_serializer.save()
            return Response({
                'success': 'Заказ %s был успешно добавлен.' % order_saved.id,
                'order': order_serializer.data
            })


Я не так давно изучаю drf и не далеко зашел в плане доков, так что буду рад даже просто ссылке на пример или на официальную документацию, просто я видимо пропустил тот момент, где в обработке запроса задействуются сразу несколько таблиц бд. Спасибо!
  • Вопрос задан
  • 301 просмотр
Подписаться 1 Средний Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы