Сбои в работе уникальных ограничений в 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