2016-03-08 128 views
4

我遇到了一些麻烦,通过参数序列化多对多关系与在DRF3在Django的REST框架中介模型序列化多对多关系

非常基本上我有配方和成分,通过指定的中间模型相结合数量和单位使用的特定成分。

这是我的模型:

from django.db import models 
from dry_rest_permissions.generics import authenticated_users, allow_staff_or_superuser 
from core.models import Tag, NutritionalValue 
from usersettings.models import Profile 

class IngredientTag(models.Model): 
    label = models.CharField(max_length=255) 

    def __str__(self): 
     return self.label 


class Ingredient(models.Model): 
    recipe = models.ForeignKey('Recipe', on_delete=models.CASCADE) 
    ingredient_tag = models.ForeignKey(IngredientTag, on_delete=models.CASCADE) 
    amount = models.FloatField() 
    unit = models.CharField(max_length=255) 


class RecipeNutrition(models.Model): 
    nutritional_value = models.ForeignKey(NutritionalValue, on_delete=models.CASCADE) 
    recipe = models.ForeignKey('Recipe', on_delete=models.CASCADE) 
    amount = models.FloatField() 


class Recipe(models.Model): 
    name = models.CharField(max_length=255) 
    ingredients = models.ManyToManyField(IngredientTag, through=Ingredient) 
    tags = models.ManyToManyField(Tag, blank=True) 
    nutritions = models.ManyToManyField(NutritionalValue, through=RecipeNutrition) 
    owner = models.ForeignKey(Profile, on_delete=models.SET_NULL, blank=True, null=True) 

    def __str__(self): 
     return self.name 

而这些都是目前我的串行:

from recipes.models import Recipe, IngredientTag, Ingredient 
from rest_framework import serializers 

class IngredientTagSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = IngredientTag 
     fields = ('id', 'label') 

class IngredientSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Ingredient 
     fields = ('amount', 'unit') 

class RecipeSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Recipe 
     fields = ('id', 'url', 'name', 'ingredients', 'tags', 'nutritions', 'owner') 
     read_only_fields = ('owner',) 
     depth = 1 

我如此搜查和网络了不少,但我想不通出来。如果有人能指引我走向正确的方向,那将会很棒。

我可以得到配料清单中返回,像这样:

{ 
    "count": 1, 
    "next": null, 
    "previous": null, 
    "results": [ 
     { 
      "id": 1, 
      "url": "http://localhost:8000/recipes/1/", 
      "name": "Hallo recept", 
      "ingredients": [ 
       { 
        "id": 1, 
        "label": "Koek" 
       } 
      ], 
      "tags": [], 
      "nutritions": [], 
      "owner": null 
     } 
    ] 
} 

但我要的是量,单位也可以退换!

+0

当'IngredientTag'上的'ManyToManyField'被设置时,为什么你期望在成分中有'amount'和'unit'? – AKS

+0

@AKS我有中间模型成分设置通过=成分。基本上,序列化现在与IngredientTag发生,我希望它与成分发生。我不知道该期待什么。我对DRF和Django是一个新鲜的东西 –

+0

请在序列化之后显示您期望在“配料”中的内容的例子吗? – AKS

回答

2

在序列化嵌套关系时,还必须特别序列化ManyToManyField。

让我给你一个小例子:

class RecipeSerializer(serializers.ModelSerializer): 

    ingredients = serializers.SerializerMethodField() 

    def get_ingredients(self, obj): 
     serializer = IngredientSerializer(obj.ingredients) 
     return serializer.data  

    class Meta: 
     model = Recipe 
     fields = ('id', 'url', 'name', 'ingredients', 'tags', 'nutritions', 'owner') 
     read_only_fields = ('owner',) 
     depth = 1 

无论你的嵌套关系(如成分,标签或营养品),你可以通过创建一个串行方法场序列化。在该方法中,您可以使用特定的序列化程序,以便为您提供所需的json。

请注意方法名称。如果你的ManyToManyField是“成分”,你的方法名应该是“成分”,因为DRF与“get_”一起工作。

欲了解更多信息,检查:

Django Rest Framework - SerializerMethodField

+0

您是否测试过它?我认为'obj.ingredients'将返回'IngredientTag'的实例,而不是'Ingredient'的实例,因为'Ingredient'是直通模型。 – AKS

+0

我没有测试,但这是我一直使用的方式。我只是没有意识到这是通过模型。我刚刚举了一个使用SerializerMethodField的例子,以便他可以完成剩下的工作。 –

+0

这种方式是正确的,但@AKS是正确的,首先,我们应该得到Ingredient query_set并将其放入序列化程序中:serializer = IngredientSerializer(query,many = True,context = self.context)...它适用于我 – nim4n

0

覆盖RecipeSerializer 的方法to_representation和许多的实例传递给很多申请自己的串行器与许多为True。或

标签= serializers.HyperlinkedRelatedField( 多=真,READ_ONLY =真, )

3

我得到了我想要的方式如下:

from recipes.models import Recipe, IngredientTag, Ingredient 
from rest_framework import serializers 

class IngredientTagSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = IngredientTag 
     fields = ('id', 'label') 

class IngredientSerializer(serializers.ModelSerializer): 
    ingredient_tag = IngredientTagSerializer() 

    class Meta: 
     model = Ingredient 
     fields = ('amount', 'unit', 'ingredient_tag') 

class RecipeSerializer(serializers.ModelSerializer): 
    ingredients = IngredientSerializer(source='ingredient_set', many=True) 

    class Meta: 
     model = Recipe 
     fields = ('url', 'name', 'ingredients', 'tags', 'nutritions', 'owner') 
     read_only_fields = ('owner',) 
     depth = 1 

使用作为IngredientSerializer来源的ingredient_tag的ingredient_set产生了我要求的响应:

{ 
    "count": 1, 
    "next": null, 
    "previous": null, 
    "results": [ 
     { 
      "url": "http://localhost:8000/recipes/1/", 
      "name": "Hallo recept", 
      "ingredients": [ 
       { 
        "amount": 200.0, 
        "unit": "g", 
        "ingredient_tag": { 
         "id": 1, 
         "label": "Koek" 
        } 
       }, 
       { 
        "amount": 500.0, 
        "unit": "kg", 
        "ingredient_tag": { 
         "id": 3, 
         "label": "Sugar" 
        } 
       } 
      ], 
      "tags": [], 
      "nutritions": [], 
      "owner": null 
     } 
    ] 
} 

我不知道这是否是最好的方法,所以我会等待直到有人知道他们的DRF留下了评论,或者有人在标记为答案之前发布了更好的东西。

+0

我想不出更好的办法。由于您没有示例输出,我不确定您想要实现什么。但是,我会采用这种方法。 – AKS

+0

您也可以从序列化程序中排除id属性,因为这是不必要的。 –

+0

@ÇağatayBarın如果你的意思是身边的网址,你是对的:) –

相关问题