Использование пользовательских методов в фильтре с django-rest-framework

Я хотел бы отфильтровать параметры запроса в моем REST API -см. документы django на этом. Однако один параметр, который я хочу фильтровать, доступен только через model @property

пример models.py:

class Listing(models.Model):
    product = models.OneToOneField(Product, related_name='listing')
    ...
    @property
    def category(self):
        return self.product.assets[0].category.name

вот настройка для моего API листинга в соответствии с django-filter docs

    class ListingFilter(django_filters.FilterSet):
        product = django_filters.CharFilter(name='product__name')
        category = django_filters.CharFilter(name='category') #DOES NOT WORK!!

        class Meta:
            model = Listing
            fields = ['product','category']

    class ListingList(generics.ListCreateAPIView):
        queryset = Listing.objects.all()
        serializer_class = ListingSerializer
        filter_class = ListingFilter

Как я могу соответствующим образом фильтровать по списку.категория? Он не доступен непосредственно в модели листинга.

2 ответов


используйте параметр 'action', чтобы указать пользовательский метод -см. django-filter docs

сначала определите метод, который фильтрует набор запросов, используя значение параметра category:

    def filter_category(queryset, value):
        if not value:
            return queryset

        queryset = ...custom filtering on queryset using 'value'...
        return queryset

фильтр список должен выглядеть так:

    class ListingFilter(django_filters.FilterSet):
        ...
        category = django_filters.CharFilter(action=filter_category)
        ...

ради скорости базы данных, вы должны просто добавить категорию в каталоге модель

class Listing(models.Model):
    product = models.OneToOneField(Product, related_name='listing')
    category = models.ForeignKey(Category)

затем использовать post_save сигнал для обновления поля

from django.dispatch import receiver
from django.db.models.signals import post_save

@receiver(post_save, sender=Product)
def updateCategory(sender, instance, created, update_fields, **kwargs):
    product = instance
    product.listing.category = product.assets[0].category.name
    product.listing.save()

затем фильтровать по его имени, как и любое другое поле:

class ListingFilter(django_filters.FilterSet):
    ...
    category = django_filters.CharFilter(name='category__name')
    ...