在django-rest-framework中使用自定义方法过滤

15 投票
2 回答
22280 浏览
提问于 2025-04-18 11:04

我想在我的REST API中根据查询参数进行过滤 - 可以查看Django的文档。不过,有一个我想要过滤的参数只能通过模型的@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

这是我根据django-filter文档设置的Listing API。

    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

我该如何正确地根据listing.category进行过滤呢?因为这个属性在listing模型中并不是直接可用的。

2 个回答

-2

为了提高数据库的速度,你应该直接在你的列表模型中添加分类。

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')
    ...
23

使用'action'参数来指定一个自定义的方法 - 查看django-filter文档

首先定义一个方法,这个方法会根据类别参数的值来过滤查询集:

    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)
        ...

撰写回答