Сбои в работе уникальных ограничений в Django

Я пытаюсь создать планировщик питания с помощью react и django. У меня проблемы с формой и получением данных в бэкенд. Сейчас я могу отправить форму из react и получить данные обратно в django правильно. Пока мне не нужно добавить еще один mealItem для той же даты и serviceType ('lunch', 'dinner'). Я получаю ошибку уникального ограничения для следующих полей: "meals_meal.menu_id, meals_meal.date, meals_meal.type, meals_meal.url".

Мои варианты - либо переделать форму на фронтенде, либо изменить способ работы с данными на бэкенде. На переднем конце у меня есть кнопка, которая добавляет форму. В зависимости от нажатия кнопки выбирается дата, тип услуги и тип сервиса для отправки в бэкэнд. Форма имеет текстовый ввод для названия элемента, тип ('entre','side','other') и тип диеты ('vegetarian', gluten_free, diary_free)

Любая помощь в решении этой проблемы была бы потрясающей, спасибо. Я должен добавить, что большая часть модели была создана моим шурином, но из-за того, что я знал члена семьи. У него не так много времени, чтобы помочь мне.

Models.py

class Menu(models.Model):
    name = models.CharField(max_length=100)
    users = models.ManyToManyField(User, related_name='menus')
    created_at = models.DateTimeField(
        auto_now_add=True,
        editable=False,
    )
    updated_at = models.DateTimeField(
        auto_now=True,
        editable=False,
    )

    

    def __str__(self):
        return self.name


class MealQuerySet(models.QuerySet):
    def week_of(self, date):
        return self.filter(date__range=week_range(date))


class Meal(models.Model):
    menu = models.ForeignKey(
        Menu,
        related_name='meals',
        on_delete=models.CASCADE,
    )
    date = models.DateField(db_index=True)
    type = models.CharField(
        choices=[
            ('lunch', 'Lunch'),
            ('dinner', 'Dinner'),
        ],
        max_length=10,
    )
    url = models.URLField(max_length=200, default="")
    created_at = models.DateTimeField(
        auto_now_add=True,
        editable=False,
    )
    updated_at = models.DateTimeField(
        auto_now=True,
        editable=False,
    )
    objects = MealQuerySet.as_manager()

    class Meta:
        unique_together = ['menu', 'date', 'type', 'url']
        ordering = ['date', '-type']


class MealItem(models.Model):
    meal = models.ForeignKey(
        Meal,
        related_name='items',
        on_delete=models.CASCADE,
    )
    name = models.CharField(max_length=100)
    type = models.CharField(
        choices=[
            ('entre', 'Entre'),
            ('side', 'Side'),
            ('other', 'Other'),
        ],
        max_length=10,
    )
    is_dairy_free = models.BooleanField(
        default=False,
        verbose_name='D',
        help_text='Dairy Free',
    )
    is_gluten_free = models.BooleanField(
        default=False,
        verbose_name='G',
        help_text='Gluten Free',
    )
    is_vegetarian = models.BooleanField(
        default=False,
        verbose_name='V',
        help_text='Vegetarian',
    )
    created_at = models.DateTimeField(
        auto_now_add=True,
        editable=False,
    )
    updated_at = models.DateTimeField(
        auto_now=True,
        editable=False,
    )


class ClientHouse(models.Model):
    name = models.CharField(max_length=100 )
    house_menu = models.ForeignKey(Menu, related_name='menu', on_delete=models.CASCADE)
    password = models.CharField(max_length=20)

    def __str__(self):
        return self.name

Serializers.py

class MenuSerializer(serializers.ModelSerializer):
    class Meta:
        model = Menu
        fields = ['id', 'name']


class MealItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = MealItem
        fields = ['name', 'type', 'is_dairy_free',
                  'is_gluten_free', 'is_vegetarian', ]


class MealSerializer(serializers.ModelSerializer):
    items = MealItemSerializer(many=True)
    class Meta:
        model = Meal
        fields = ['id', 'date', 'type','url', 'items', 'menu', ]
        validators = []


    def create(self, validated_data):
        item_data = validated_data.pop('items')
        meal= Meal.objects.create(**validated_data)
        for item_data in item_data:
            MealItem.objects.get_or_create(meal=meal, **item_data)
        return meal
    
    def update(sel, instance, validated_data):
        instance.id = validated_data.get('id', instance.id)
        instance.date = validated_data.get('date', instance.date)
        instance.type = validated_data.get('type', instance.type)
        instance.save()
        return instance

class ClientSerializer(serializers.ModelSerializer):

    class Meta:
        model = ClientHouse
        fields = ['id', 'name', 'house_menu', 'password']

class UserSerializer(serializers.ModelSerializer):
    user_permissions = serializers.SerializerMethodField()

    class Meta:
        model = User
        fields = ('id', 'username', 'user_permissions')

    def get_user_permissions(self, obj):
        print(obj)
        return obj.user_permissions.all()

Views.Py

Это результат, который мне нужно получить. Но сейчас я отправляю только одно блюдо за раз в массив items. В отличие от добавления всех трех блюд, как я делаю в панели добавления блюд администратора django.

            "id": 1,
            "date": "2021-11-17",
            "type": "lunch",
            "url": "#ImageUrlFromFirebase",
            "items": [
                {
                    "name": "milk",
                    "type": "entre",
                    "is_dairy_free": false,
                    "is_gluten_free": false,
                    "is_vegetarian": true
                },
                {
                    "name": "beans",
                    "type": "side",
                    "is_dairy_free": false,
                    "is_gluten_free": true,
                    "is_vegetarian": false
                },
                {
                    "name": "sleep",
                    "type": "other",
                    "is_dairy_free": true,
                    "is_gluten_free": false,
                    "is_vegetarian": false
                }
            ],
            "menu": 1
        },

Метод обновления вызывается, когда тип запроса PUT и соответствующий этому должен быть update метод на вашем Viewset, который отсутствует, кажется? Также, если обновление частичное (то есть только некоторые поля будут обновлены), то partial = True (должен быть), для ссылки https://www.django-rest-framework.org/tutorial/2-requests-and-responses/

В идеале, я бы создал другой набор представлений с именем MealItemViewset, который затем будет иметь метод update, чтобы мы могли отделить creation, deletion and updating от Meals и MealItems

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