【问题标题】:Creating/Updating Model with Multiple "ManyToMany" and "through" Relationships创建/更新具有多个“ManyToMany”和“through”关系的模型
【发布时间】:2020-02-09 05:26:34
【问题描述】:

我正在 django-rest-framework 中为我的移动应用程序创建一个 Rest API。我的应用程序类似于 MyFitnessPal,所以我的用户有自己的饮食历史,他们的餐点在哪里,每餐都有食品清单。

现在,当我注册用户时,我正在为他创建一个新的、空的 FoodHistory。

所以接下来我想添加添加/更新这些餐点的选项。当用户想要将食品添加到日期为 10-10.2019 的“早餐”中时,我想检查该日期的“早餐”是否已经存在于用户的历史记录中。如果不是,则创建它(并将“meal_date”参数设置为请求的日期),如果是,则使用其 ID(已创建)将 Food product form DB 获取并使用“food_weight”参数将其添加到用户的历史记录中。

当我有多个多对多并通过关系时,我不知道该怎么做。我知道我必须覆盖 serializers.py 中的“create”和“update”方法以及“api.py”中的“post”方法,但现在我什至不确定哪个序列化程序应该在我的 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)

序列化器.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"
            }
        ]
    }
}

【问题讨论】:

    标签: python django django-models django-rest-framework django-serializer


    【解决方案1】:

    您的 Serializer 类必须包含模型 MealDate,使用 APIVIEW 创建自定义 post 方法。 首先,创建 UserFoodHistory 实例,然后在 MealDate 中创建一个批量条目,并在 user_food_history 字段中传递该实例。

    在 post API 中传递新旧 id 以及从请求和 APIVIEW 中删除 MealDate 中的旧条目(如果存在)并创建一个新条目。

    【讨论】:

      猜你喜欢
      • 2012-02-27
      • 2018-08-01
      • 2017-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多