如何使用Django Filters按两个字段范围过滤模型数据?
用Django Filters实现年龄区间过滤
首先得先装好django-filter工具:
pip install django-filter
然后在项目的settings.py里把它加到INSTALLED_APPS:
INSTALLED_APPS = [ # 其他已有的app 'django_filters', ]
接下来分两种常见场景实现过滤:
场景1:根据单个年龄值筛选
比如用户输入年龄25,要找出所有min_age ≤25 ≤max_age的广告,同时兼容字段为空的情况(min_age为空表示无年龄下限,max_age为空表示无年龄上限)。
创建filters.py文件,定义过滤器类:
import django_filters from .models import AdvertisementModelMixin class AdvertisementFilter(django_filters.FilterSet): # 自定义一个age参数用来接收输入的年龄值 age = django_filters.NumberFilter(method='filter_by_age_range') class Meta: model = AdvertisementModelMixin fields = ['age'] def filter_by_age_range(self, queryset, name, value): # 构造过滤条件:满足年龄在广告的区间内,或区间无上下限 return queryset.filter( django_filters.Q(min_age__lte=value) | django_filters.Q(min_age__isnull=True), django_filters.Q(max_age__gte=value) | django_filters.Q(max_age__isnull=True) )
在视图里使用这个过滤器,比如普通列表视图:
# views.py from django.views.generic import ListView from .models import AdvertisementModelMixin from .filters import AdvertisementFilter class AdvertisementListView(ListView): model = AdvertisementModelMixin template_name = 'advertisement_list.html' def get_queryset(self): queryset = super().get_queryset() # 用请求参数初始化过滤器,返回过滤后的查询集 return AdvertisementFilter(self.request.GET, queryset=queryset).qs
前端只需要传/?age=25就能拿到符合条件的广告列表。
场景2:根据输入的年龄范围筛选
比如用户输入18到30,要找出所有和这个范围有交集的广告区间。
修改filters.py:
import django_filters from .models import AdvertisementModelMixin class AdvertisementFilter(django_filters.FilterSet): from_age = django_filters.NumberFilter(method='filter_by_age_range') to_age = django_filters.NumberFilter(method='filter_by_age_range') class Meta: model = AdvertisementModelMixin fields = ['from_age', 'to_age'] def filter_by_age_range(self, queryset, name, value): from_age = self.request.GET.get('from_age') to_age = self.request.GET.get('to_age') if not from_age and not to_age: return queryset q = django_filters.Q() if from_age: # 广告的上限要大于等于输入的起始年龄,或广告无上限 q &= django_filters.Q(max_age__gte=from_age) | django_filters.Q(max_age__isnull=True) if to_age: # 广告的下限要小于等于输入的结束年龄,或广告无下限 q &= django_filters.Q(min_age__lte=to_age) | django_filters.Q(min_age__isnull=True) return queryset.filter(q)
前端传/?from_age=18&to_age=30就能得到符合条件的结果。
如果是用Django REST Framework,直接在视图集里配置过滤器即可:
# views.py(DRF) from rest_framework import viewsets from .models import AdvertisementModelMixin from .serializers import AdvertisementSerializer from .filters import AdvertisementFilter class AdvertisementViewSet(viewsets.ModelViewSet): queryset = AdvertisementModelMixin.objects.all() serializer_class = AdvertisementSerializer filter_class = AdvertisementFilter
内容的提问来源于stack exchange,提问作者rowsen
相关产品推荐
相关产品推荐

