Django(69)最好用的過濾器外掛Django-filter

Silent丿丶黑羽發表於2021-06-23

前言

  如果需要滿足前端各種篩選條件查詢,我們使用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

Djangosettings.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中表單類極其類似,寫法基本一樣,目的是指明過濾的時候使用哪些欄位進行過濾,每個欄位可以使用哪些運算。運算子的寫法基本參照DjangoORM中查詢的寫法,比如:大於等於,小於等於用"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查詢的時候可以進行包含查詢,icontainsORM中表示不區分大小的包含

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

相關文章