目录
数据准备
分类筛选 filter_fields
区间筛选 filter_class
DjangoFilterBackend 部分源码解析
数据准备
model.py 文件
定义两个表 Car 表和 Brand 表, 其中 Car 中的 brand 字段外键关联 Brand 表
- from django.db import models
- class BaseModel(models.Model):
- is_delete = models.BooleanField(default=False)
- create_time = models.DateTimeField(auto_now_add=True)
- class Meta:
- abstract = True
- class Car(BaseModel):
- name = models.CharField(max_length=32)
- price = models.DecimalField(max_digits=5, decimal_places=2)
- brand = models.ForeignKey('Brand', db_constraint=False, on_delete=models.DO_NOTHING, related_name='cars')
- @property
- def brand_name(self):
- return self.brand.name
- class Meta:
- db_table = 'old_boy_car'
- verbose_name = '汽车'
- verbose_name_plural = verbose_name
- def __str__(self):
- return self.name
- class Brand(BaseModel):
- name = models.CharField(max_length=32)
- class Meta:
- db_table = 'old_boy_brand'
- verbose_name = '品牌'
- verbose_name_plural = verbose_name
- def __str__(self):
- return self.name
新建的 serializer.py 文件
brand 字段只参与反序列化, brand_name 只参与序列化
- from rest_framework.serializers import ModelSerializer
- from . import models
- class CarModelSerializer(ModelSerializer):
- class Meta:
- model = models.Car
- fields = ('name','price','brand','brand_name')
- extra_kwargs = {
- "brand":{
- 'write_only':True
- },
- 'brand_name':{
- 'read_only':True
- },
- }
分类筛选 filter_fields
views.py 文件
- from rest_framework.viewsets import ModelViewSet
- from . import models, serializer
- from django_filters.rest_framework import DjangoFilterBackend
- class CarModelViewSet(ModelViewSet):
- queryset = models.Car.objects.filter(is_delete=False)
- serializer_class = serializer.CarModelSerializer
- filter_backends = [DjangoFilterBackend]
- # 分类: 一般都是可以分组的字段
- filter_fields = ['brand']
- # 按品牌 brand 分类, url 链接:/car/?brand=1
区间筛选 filter_class
新建的 filterset.py
max_price 与 min_price 是用于参与区间分类, 不写也可以仅做分类同 filter_fields 效果一样
- from django_filters import FilterSet,filters
- from . import models
- class CarFilterSet(FilterSet):
- max_price = filters.NumberFilter(field_name='price',lookup_expr='lte')
- min_price = filters.NumberFilter(field_name='price',lookup_expr='gte')
- class Meta:
- model = models.Car
- # brand 还是实现分类
- fields = ['brand','max_price','min_price']
views.py 文件
- from rest_framework.viewsets import ModelViewSet
- from . import models, serializer
- from django_filters.rest_framework import DjangoFilterBackend
- from .filterset import CarFilterSet
- class CarModelViewSet(ModelViewSet):
- queryset = models.Car.objects.filter(is_delete=False)
- serializer_class = serializer.CarModelSerializer
- filter_backends = [DjangoFilterBackend]
- filter_class = CarFilterSet
- # url 链接:/car/?max_price=100 价格不超过 100
- # url 链接:/car/?min_price=10 价格不低于 10
- # url 链接:/car/?brand=1&min_price=10&max_price=100 品牌 brand 为 1 且价格在 [10,100] 内的汽车
DjangoFilterBackend 部分源码解析
1. 在 DjangoFilterBackend 组件中先调用 filter_queryset 方法中
- def filter_queryset(self, request, queryset, view):
- filterset = self.get_filterset(request, queryset, view) # 获取筛选条件
- # 如果 filterset 为 None, 表示没有筛选条件
- if filterset is None:
- return queryset
- # 无效的筛选条件处理
- if not filterset.is_valid() and self.raise_exception:
- raise utils.translate_validation(filterset.errors)
- return filterset.qs
2. 调用 get_filterset 方法获取 filterset
- def get_filterset(self, request, queryset, view):
- filterset_class = self.get_filterset_class(view, queryset) # 获取筛选类
- if filterset_class is None:
- return None
- kwargs = self.get_filterset_kwargs(request, queryset, view)
- return filterset_class(**kwargs)
3. 调用 get_filterset_class 方法获取 filterset_class
- def get_filterset_class(self, view, queryset=None):
- """
- Return the `FilterSet` class used to filter the queryset.
- """ filterset_class = getattr(view,'filterset_class', None)
- filterset_fields = getattr(view, 'filterset_fields', None)
- # 将 filter_class 映射给 filterset_class
- if filterset_class is None and hasattr(view, 'filter_class'):
- utils.deprecate(
- "`%s.filter_class` attribute should be renamed `filterset_class`."
- % view.__class__.__name__)
- filterset_class = getattr(view, 'filter_class', None)
- # 将 filter_fields 映射给 filterset_fields
- if filterset_fields is None and hasattr(view, 'filter_fields'):
- utils.deprecate(
- "`%s.filter_fields` attribute should be renamed `filterset_fields`."
- % view.__class__.__name__)
- filterset_fields = getattr(view, 'filter_fields', None)
- # 有 filterset_class 时执行, filterset_class 定义的是一个类
- if filterset_class:
- filterset_model = filterset_class._meta.model
- # FilterSets do not need to specify a Meta class
- if filterset_model and queryset is not None:
- assert issubclass(queryset.model, filterset_model), 'FilterSet model %s does not match queryset model %s' % (filterset_model, queryset.model)
- return filterset_class
- # 有 filterset_fields 时执行
- if filterset_fields and queryset is not None:
- MetaBase = getattr(self.filterset_base, 'Meta', object)
- class AutoFilterSet(self.filterset_base):
- class Meta(MetaBase):
- model = queryset.model
- fields = filterset_fields
- return AutoFilterSet
- return None
来源: http://www.bubuko.com/infodetail-3198918.html