前言
如果需要滿足前端各種篩選條件查詢,我們使用drf
自帶的會比較麻煩,比如查詢書名中包含“國”字,日期大於“2020-1-1”等等諸如此類的請求,Django-filter
這個元件就是要解決這樣的問題。
1.安裝
Django-filter
支援的Python
版本和Django
版本、DRF
版本如下:
- Python: 3.5, 3.6, 3.7, 3.8
- Django: 1.11, 2.0, 2.1, 2.2, 3.0
- DRF: 3.10+
在虛擬環境中安裝
pip3 install django-filter
在Django
的settings.py
檔案中安裝並配置django_filters
應用:
INSTALLED_APPS = [
...
'django_filters',
]
REST_FRAMEWORK = {
# 過濾器預設後端
'DEFAULT_FILTER_BACKENDS': (
'django_filters.rest_framework.DjangoFilterBackend',),
}
2.使用流程
我們通過一個簡單的圖書查詢來說明如果在DRF中使用Django-filter
過濾器。圖書模型如下:
# models.py
class BookInfo(models.Model):
title = models.CharField(max_length=200,verbose_name='標題')
pub_date = models.DateField(blank=True, null=True,verbose_name='出版日期')
read = models.IntegerField(null=True,verbose_name='閱讀數量')
comment = models.IntegerField(null=True,verbose_name='評論數量')
image = models.CharField(max_length=200, blank=True, null=True,verbose_name='圖片')
class Meta:
db_table = 'bookInfo'
verbose_name = "圖書"
序列化類:
# serializers.py
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = BookInfo
fields = '__all__'
自定義過濾器類:
# filters.py
from django_filters import rest_framework as filters
from . models import BookInfo
class BookFilter(filters.FilterSet):
min_read = filters.NumberFilter(field_name="read", lookup_expr='gte')
max_read = filters.NumberFilter(field_name="read", lookup_expr='lte')
class Meta:
model = BookInfo
fields = ['read']
在檢視中
# views.py
class BookView(ListAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookSerializer
filter_class = BookFilter
url配置中
app_name = "api"
urlpatterns = [
path('books/', views.BookView.as_view()),
]
現在我們想篩選閱讀數為500-1000的圖書,測試結果如下
詳解過濾器類
過濾器類和Django
中表單類極其類似,寫法基本一樣,目的是指明過濾的時候使用哪些欄位進行過濾,每個欄位可以使用哪些運算。運算子的寫法基本參照Django
的ORM
中查詢的寫法,比如:大於等於,小於等於用"gte"
,"lte"
等等
可以通過模型快速構建過濾器類
from django_filters import rest_framework as filters
class BookFilter(filters.FilterSet):
class Meta:
model = BookInfo # 模型名
fields = ['title','comment'] # 可以使用的過濾欄位
Meta
中出現的fields
是指過濾條件中可以出現的欄位,預設是精確判斷相等,查詢的時候可以這樣用:
http://127.0.0.1:8000/api/books/?comment=20&title=
以上代表查詢的是評論條數為20條的書本
如果不是判斷相等,可以自定義過濾欄位進行過濾:
- 過濾器中常用的欄位型別,這些型別要輸模型中對應欄位型別相容
CharFilter 字串型別
BooleanFilter 布林型別
DateTimeFilter 日期時間型別
DateFilter 日期型別
DateRangeFilter 日期範圍
TimeFilter 時間型別
NumberFilter 數值型別,對應模型中IntegerField, FloatField, DecimalField
- 過濾欄位引數說明:
field_name: 過濾欄位名,一般應該對應模型中欄位名
lookup_expr: 查詢時所要進行的操作,和ORM中運算子一致
- Meta欄位說明
model: 引用的模型,不是字串
fields:指明過濾欄位,可以是列表,列表中字典可以過濾,預設是判斷相等;也可以字典,字典可以自定義操作
exclude = ['password'] 排除欄位,不允許使用列表中字典進行過濾
自定義過濾欄位:
class BookFilter(filters.FilterSet):
title = filters.CharFilter(field_name='title',lookup_expr='icontains') # 標題中包含
pub_year = filters.CharFilter(field_name='pub_date',lookup_expr='year') # 過濾年份相等
pub_year__gt = filters.CharFilter(field_name='pub_date',lookup_expr='year__gt') # 過濾大於年份
read__gt = filters.NumberFilter(field_name='read',lookup_expr="gt") # 最大閱讀數
read__lt = filters.NumberFilter(field_name='read',lookup_expr="lt") # 最小閱讀數
class Meta:
model = BookInfo
fields = ['title','read','comment']
自定義欄位名可以和模型中不一致,但一定要用引數field_name
指明對應模型中的欄位名
日期查詢
定義按年查詢
pub_year = filters.CharFilter(field_name='pub_date',lookup_expr='year')
年份應該大於某值
pub_year__gt = filters.CharFilter(field_name='pub_date',lookup_expr='year__gt')
年份應該小於某值
read__lt = filters.NumberFilter(field_name='read',lookup_expr="lt")
查詢出版年份大於2019年的書本
http://127.0.0.1:8000/api/books/?title=&read=&comment=&pub_year=&pub_year__gt=2019&read__gt=&read__lt=
查詢結果:
[
{
"id": 1,
"title": "鋼鐵是怎樣練成的",
"pub_date": "2020-10-09",
"read": 100,
"comment": 3,
"image": null
}
]
標題查詢
title
查詢的時候可以進行包含查詢,icontains
在ORM
中表示不區分大小的包含
title = filters.CharFilter(field_name='btitle',lookup_expr='icontains')
查詢標題中包含三國演義的書籍
http://127.0.0.1:8000/api/books/?title=%E4%B8%89%E5%9B%BD%E6%BC%94%E4%B9%89&read=&comment=&pub_year=&pub_year__gt=&read__gt=&read__lt=
查詢結果:
[
{
"id": 2,
"title": "三國演義",
"pub_date": "2019-11-12",
"read": 200,
"comment": 20,
"image": null
}
]
閱讀數查詢
閱讀數大於
read__gt = filters.NumberFilter(field_name='read',lookup_expr="gt")
閱讀數小於
read__lt = filters.NumberFilter(field_name='read',lookup_expr="lt")
查詢閱讀數在100-300之間的書籍
http://127.0.0.1:8000/api/books/?title=&read=&comment=&pub_year=&pub_year__gt=&read__gt=100&read__lt=300
查詢結果:
[
{
"id": 2,
"title": "三國演義",
"pub_date": "2019-11-12",
"read": 200,
"comment": 20,
"image": null
}
]
官方文件:https://django-filter.readthedocs.io/en/stable/guide/install.html