数据准备
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