Django rest filter by serializermethodfield с пользовательским фильтром
Как заявлено в заголовке вопроса, у меня есть задача фильтровать результаты по полю, не представленному в модели, но вычисляемому сериализатором.
Вот код представления:
class RecipeViewSet(ModelViewSet):
queryset = Recipe.objects.all()
permission_classes = [IsAdminOrAuthorOrReadOnly, ]
serializer_class = RecipeInSerializer
pagination_class = LimitPageNumberPagination
filter_backends = [DjangoFilterBackend]
filterset_fields = ['tags', ]
filter_class = RecipeFilter
Serializer:
class RecipeOutSerializer(serializers.ModelSerializer):
tags = ManyRelatedField(child_relation=TagSerializer())
author = CustomUserSerializer()
ingredients = serializers.SerializerMethodField()
is_favorite = serializers.SerializerMethodField()
is_in_shopping_cart = serializers.SerializerMethodField()
class Meta:
fields = '__all__'
model = Recipe
def get_ingredients(self, obj):
ingredients = IngredientAmount.objects.filter(recipe=obj)
return GetIngredientSerializer(ingredients, many=True).data
def get_is_favorite(self, obj):
request = self.context.get("request")
if request.user.is_anonymous:
return False
return Favorite.objects.filter(recipe=obj, user=request.user).exists()
def get_is_in_shopping_cart(self, obj):
request = self.context.get("request")
if not request or request.user.is_anonymous:
return False
return ShoppingCart.objects.filter(recipe=obj, user=request.user).exists()
И код пользовательского фильтра:
class RecipeFilter(rest_framework.FilterSet):
tags = ModelMultipleChoiceFilter(
field_name='tags__slug',
to_field_name="slug",
queryset=Tag.objects.all()
)
favorite = BooleanFilter(field_name='is_favorite', method='filter_favorite')
def filter_favorite(self, queryset, name, value):
return queryset.filter(is_favorite__exact=True)
class Meta:
model = Recipe
fields = ['tags', ]
Целью является поле is_favorited, которое возвращает булево значение. Я пытался написать func в классе пользовательского фильтра, который возвращает queryset, но ничего не получилось, ни документация не помогла мне с примерами. Надеюсь на вашу помощь.
Мы можем использовать аннотацию queryset:
from django.db import models
from rest_framework import serializers
class RecipeViewSet(ModelViewSet):
def get_queryset(self):
user = self.request.user
user_id = user.id if not user.is_anonymous else None
return Recipe.objects.all().annotate(
total_favorite=models.Count(
"favorite",
filter=models.Q(favorite__user_id=user_id)
),
is_favorite=models.Case(
models.When(total_favorite__gte=1, then=True),
default=False,
output_field=BooleanField()
)
)
class RecipeOutSerializer(serializers.ModelSerializer)
is_favorite = serializers.BooleanField(read_only=True)
class Meta:
model = Recipe
fields = (
# ...
is_favorite,
)
class RecipeFilter(rest_framework.FilterSet):
favorite = BooleanFilter(field_name='is_favorite')