Search code examples
pythondjangodjango-modelsdjango-rest-frameworkdjango-queryset

Django REST Framework: can't properly annotate values to many-to-many model, keep getting error Field name <field> is not valid for model <m2m model>


I have a model for recipes and many-to-many model that represents favorite recipes by users:

class Recipe(models.Model):
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    name = models.CharField(max_length=LENGTH_FOR_TEXTFIELD)
    image = models.ImageField()
    text = models.TextField(max_length=LENGTH_FOR_TEXTFIELD)
    cooking_time = models.PositiveSmallIntegerField()

    def __str__(self):
        return self.name
class FavoriteRecipe(models.Model):
    recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
    user = models.ForeignKey(User, on_delete=models.CASCADE)

    def __str__(self):
        return self.recipe.name

After POST request an entry in that model is created (recipe ID and user ID) and i am trying to write a serializer for response that will contain info about recipe itself:

class FavoriteRecipeSerializerForRead(serializers.ModelSerializer):

    class Meta:
        model = FavoriteRecipe
        fields = ('id', 'name', 'image', 'cooking_time')

So the problem is that i cannot insert into this serializer any recipe-field because i keep getting error:

django.core.exceptions.ImproperlyConfigured: Field name `name` is not valid for model `FavoriteRecipe`

I tried to imply select_related() and .annotate(field=Value(Query)) in my viewset like this but nothing seems to work:

class FavoriteRecipeViewSet(viewsets.ModelViewSet):
    queryset = FavoriteRecipe.objects.all()
    serializer_class = FavoriteRecipeSerializerForRead

    def get_queryset(self):
        queryset = FavoriteRecipe.objects.all().annotate(
            name=Value(
                Recipe.objects.filter(id=self.id).values('cooking_time',)
            )
        )
        return queryset

The question is: how could i do this the proper way?


Solution

  • Why not serialize the Recipe?

    class RecipeSerializer(serializers.ModelSerializer):
        class Meta:
            model = Recipe
            fields = ('id', 'name', 'image', 'cooking_time')

    we can use this for Recipes that are not a Favorite one.

    In the ViewSet, we can work with the favorite Recipes of a user:

    class FavoriteRecipeViewSet(viewsets.ModelViewSet):
        queryset = Recipe.objects.all()
        serializer_class = RecipeSerializer
    
        def get_queryset(self):
            return Recipe.objects.filter(favoriterecipe__user=self.request.user)

    You will need to add authentication [drf-doc] to ensure there is a request.user.