Создание / обновление модели с несколькими отношениями «ManyToMany» и «через» - PullRequest
0 голосов
/ 11 октября 2019

Я создаю Rest API для моего мобильного приложения в django-rest-framework. Мое приложение похоже на MyFitnessPal, поэтому у моих пользователей есть своя история еды, где находятся их блюда, и у каждого приема пищи есть список продуктов питания.

На данный момент, когда я регистрирую пользователя, я создаю для него новую, пустую историю еды.

Так что в качестве следующего я хочу добавить опцию добавления / обновления этих блюд. Когда пользователь хочет добавить продукты в «Завтрак» с датой 10-10.2019, я хочу проверить, существует ли уже еда «Завтрак» с этой датой в истории пользователя. Если нет, создайте его (и задайте для параметра «food_date» дату из запроса), если да, возьмите БД формы «Продукт питания», используя ее идентификатор (он уже создан) и добавьте его в историю пользователя с параметром «food_weight».

Я не знаю, как это сделать, когда у меня есть несколько ManyToMany и через отношения. Я знаю, что я должен переопределить методы "create" и "update" в serializers.py и метод "post" в моем "api.py", но теперь я даже не уверен, какой сериализатор должен быть в моем классе APIView (api.py)как "serializer_class".

models.py

class Food(models.Model):
    name = models.CharField(max_length=255)
    brand = models.CharField(max_length=255, default="")
    energy_value = models.DecimalField(max_digits=6, decimal_places=3)
    fats = models.DecimalField(max_digits=6, decimal_places=3)
    saturated_fats = models.DecimalField(
        max_digits=6, decimal_places=3, default=0)
    carbohydrates = models.DecimalField(max_digits=6, decimal_places=3)
    sugars = models.DecimalField(max_digits=6, decimal_places=3, default=0)
    proteins = models.DecimalField(max_digits=6, decimal_places=3)
    salt = models.DecimalField(max_digits=6, decimal_places=3, default=0)

class MealType(ChoiceEnum):
    BF = "Breakfast"
    BR = "Brunch"
    DN = "Dinner"
    LN = "Lunch"
    SU = "Supper"


class Meal(models.Model):
    food = models.ManyToManyField(Food, through='FoodDetails')
    meal_type = EnumChoiceField(enum_class=MealType, null=True)


class FoodDetails(models.Model):
    meal = models.ForeignKey(Meal, on_delete=models.CASCADE)
    food = models.ForeignKey(Food, on_delete=models.CASCADE)
    food_weight = models.DecimalField(
        max_digits=6, decimal_places=3, default=100)


class UserFoodHistory(models.Model):
    meal = models.ManyToManyField(Meal, through='MealDate')


class MealDate(models.Model):
    user_food_history = models.ForeignKey(
        UserFoodHistory, on_delete=models.CASCADE)
    meal = models.ForeignKey(Meal, on_delete=models.CASCADE)
    meal_date = models.DateField(default=timezone.now, null=True)


class AppUser(AbstractUser):
    food_history = models.ForeignKey(
        UserFoodHistory, on_delete=models.CASCADE, null=True)

serializers.py

class FoodSerializer(serializers.ModelSerializer):
    class Meta:
        model = Food
        fields = '__all__'

class FoodDetailsSerializer(serializers.ModelSerializer):
    food = serializers.ReadOnlyField(source='food.id')

    class Meta:
        model = FoodDetails
        fields = ('id', 'food', 'food_weight')


class MealSerializer(serializers.ModelSerializer):
    food = FoodDetailsSerializer(source='fooddetails_set', many=True)

    class Meta:
        model = Meal
        fields = ('id', 'meal_type', 'food')


class MealDateSerializer(serializers.ModelSerializer):
    meal = serializers.ReadOnlyField(source='meal.id')

    class Meta:
        model = MealDate
        fields = ('id', 'meal', 'meal_date')


class UserFoodHistorySerializer(serializers.ModelSerializer):
    meal = MealDateSerializer(source='mealdate_set', many=True)

    class Meta:
        model = UserFoodHistory
        fields = ('id', 'meal')


class UserSerializer(serializers.ModelSerializer):
    food_history = UserFoodHistorySerializer()

    class Meta:
        model = AppUser
        fields = ('id', 'username', 'email', 'food_history')

Я хочу выполнить запрос POST примерно так:

{
"user_id": 1,
"meal_date": "10-10-2019",
"meal_type": "BR",
"food_id": 12,
"food_weight": 120
}

Теперь я могу все создавать только через админ-панель, и все выглядит хорошо, как ответ:

{
    "id": 2,
    "username": "kom1",
    "email": "kom1@wp.pl",
    "food_history": {
        "id": 1,
        "meal": [
            {
                "id": 1,
                "meal": 1,
                "meal_date": "2019-10-11"
            },
            {
                "id": 2,
                "meal": 6,
                "meal_date": "2019-10-11"
            },
            {
                "id": 3,
                "meal": 2,
                "meal_date": "2019-10-11"
            },
            {
                "id": 4,
                "meal": 3,
                "meal_date": "2019-10-11"
            },
            {
                "id": 5,
                "meal": 4,
                "meal_date": "2019-10-11"
            },
            {
                "id": 6,
                "meal": 5,
                "meal_date": "2019-10-11"
            }
        ]
    }
}

1 Ответ

0 голосов
/ 12 октября 2019

Ваш класс Serializer должен содержать модель MealDate , создать пользовательский метод post с помощью APIVIEW. Прежде всего, создайте UserFoodHistory экземпляр, а затем создайте массовую запись в MealDate с передачей этого экземпляра в user_food_history поле.

InAPI post передает старый и новый идентификатор и из запроса и в APIVIEW удаляет старые записи (если они существуют) в MealDate и создает новую.

...