Problems on through model with Django Rest Framework

This happens when I list to Recipe objects. Trying to do as here, I get no errors, but the response I'm getting is as the following:

# response of Recipe.objects.all()
[
    {
        "user": 1,
        "name": "sandwich",
        "ingredients": [
            {},
            {}
        ],
        "created": "2021-01-11T00:47:04.932071-03:00",
        "modified": "2021-01-11T00:47:04.932167-03:00"
    }
]

When the models are:

class Recipe(models.Model):
    user = models.ForeignKey('users.User', on_delete=models.CASCADE, null=False)
    name = models.CharField(blank=False, max_length=50)
    ingredients = models.ManyToManyField('recipes.Ingredient', through='recipes.IngredientComposition')
    # some other fields...

class Ingredient(BaseModel):
    name = models.CharField(blank=False, max_length=25, unique=True
                            error_messages={'unique': 'Ingredient already exists'})

class IngredientComposition(models.Model):    
    ingredient = models.ForeignKey('Ingredient', on_delete=models.CASCADE, null=False)
    recipe = models.ForeignKey('recipes.Recipe', on_delete=models.CASCADE, null=False)
    quantity = models.DecimalField(max_digits=21, decimal_places=3, null=False, default=1)

And their serializers:

class RecipeSerializer(serializers.ModelSerializer):
    ingredients = IngredientCompositionSerializer(read_only=True, many=True)
    class Meta:
        model = Recipe
        fields = ['user', 'name', 'ingredients', 'created', 'modified']

class IngredientSerializer(serializers.ModelSerializer):
    class Meta:
        model = Ingredient
        fields = ['name', 'created', 'modified']

class IngredientCompositionSerializer(serializers.HyperlinkedModelSerializer):
    name = serializers.ReadOnlyField(source='ingredient.name')
    class Meta:
        model = IngredientComposition
        fields = ['name', 'quantity']

The expected response is:

[
    {
        "user": 1,
        "name": "sandwich",
        "ingredients": [
            {"name": "bread", "quantity": 2.0},
            {"name": "cheese", "quantity": 3.0}
        ],
        "created": "2021-01-11T00:47:04.932071-03:00",
        "modified": "2021-01-11T00:47:04.932167-03:00"
    }
]

What am I missing?

1 answer

  • answered 2021-01-11 09:33 ashwin bande

    add a related name to recipe

    class IngredientComposition(models.Model):    
        ingredient = models.ForeignKey('Ingredient', on_delete=models.CASCADE, null=False)
        recipe = models.ForeignKey('recipes.Recipe', on_delete=models.CASCADE, null=False, related_name='ingredients_list') # change here
        quantity = models.DecimalField(max_digits=21, decimal_places=3, null=False, default=1)
    

    then add that field in RecipeSerializer

    class RecipeSerializer(serializers.ModelSerializer):
        ingredients_list = IngredientCompositionSerializer(read_only=True, many=True) # change here
        class Meta:
            model = Recipe
            fields = ['user', 'name', 'ingredients_list', 'created', 'modified'] # change here 'ingredients_list'
    

    as ingredients is already ManyToManyField in model Recipe it it causing that problem.

    PS: In my opinion you should not need ingredients = models.ManyToManyField('recipes.Ingredient', through='recipes.IngredientComposition') field but I dont know rest of your business logic...

    the solution should work regardless.