1. 程式人生 > 其它 >django-filter詳解

django-filter詳解

過濾元件django-filter

官方文件:https://django-filter.readthedocs.io/en/main/

1 安裝

pip install django-filter

在django配置檔案中註冊app

INSTALLED_APPS = [
    ...
    'django_filters',  # 需要註冊應用,
]

環境需求:

  • Python: 3.6, 3.7, 3.8
  • Django: 2.2, 3.1, 3.2
  • DRF: 3.10+

2 使用

給出一個模型表:

from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=255)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    description = models.TextField()
    release_date = models.DateField()
    manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)

模型表有很多欄位,我們想按照價格和日期排序,可以這樣做

import django_filters   # 匯入模組

class ProductFilter(django_filters.FilterSet):
    name = django_filters.CharFilter(lookup_expr='iexact')

    class Meta:
        model = Product
        fields = ['price', 'release_date']

django-filter支援跨表操作,也可以使用雙下劃線查詢,這樣會使過濾類顯得很冗長,但是保持了最大的自定義程度:

class ProductFilter(django_filters.FilterSet):
    price = django_filters.NumberFilter()
    price__gt = django_filters.NumberFilter(field_name='price', lookup_expr='gt')
    price__lt = django_filters.NumberFilter(field_name='price', lookup_expr='lt')

    release_year = django_filters.NumberFilter(field_name='release_date', lookup_expr='year')
    release_year__gt = django_filters.NumberFilter(field_name='release_date', lookup_expr='year__gt')
    release_year__lt = django_filters.NumberFilter(field_name='release_date', lookup_expr='year__lt')

    manufacturer__name = django_filters.CharFilter(lookup_expr='icontains')

    class Meta:
        model = Product
        fields = ['price', 'release_date', 'manufacturer']

過濾器有兩個主要引數:

  • field_name:欄位名稱,你可以使用django中的雙下劃線查詢語法來使用
  • lookup_expr:過濾時的過濾條件,支援雙下劃線語法

有關雙下劃線查詢,詳見這裡

欄位field_name和lookup_expr一起表示一個完整的Django查詢表示式。比如price__gt = django_filters.NumberFilter(field_name='price', lookup_expr='gt')定義之後,瀏覽器get請求攜帶引數price__gt=10,就會根據price欄位過濾出符合條件價格大於10的資料。

在Meta類中,model指定要過濾的模型表,fields指定通過哪些欄位來過濾。此外,可以使用字典為每個欄位指定多個查詢表示式:

import django_filters

class ProductFilter(django_filters.FilterSet):
    class Meta:
        model = Product
        fields = {
            'price': ['lt', 'gt'],
            'release_date': ['exact', 'year__gt'],
        }

如果包含外來鍵欄位,同樣可以使用雙下劃線語法:

class ProductFilter(django_filters.FilterSet):
    class Meta:
        model = Product
        fields = ['manufacturer__country']

3 drf中使用

在drf中使用過濾:

from django_filters import rest_framework as filters
# 匯入並繼承FilterSet類
class ProductFilter(filters.FilterSet):
    ...

你的檢視類還需要將DjangoFilterBackend新增到filter_backend中(區域性配置)

from django_filters import rest_framework as filters

class ProductList(generics.ListAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    filter_backends = (filters.DjangoFilterBackend,) # 配置filter_backends
    filterset_fields = ('category', 'in_stock')

全域性配置:

REST_FRAMEWORK = { # 全域性配置
    ...
    'DEFAULT_FILTER_BACKENDS': (
        'django_filters.rest_framework.DjangoFilterBackend',
    ),
}

要使用FilterSet過濾,需要將其新增到檢視類的filterset_class引數中。

from rest_framework import generics
from django_filters import rest_framework as filters
from myapp import Product

# 定義過濾類
class ProductFilter(filters.FilterSet):
    min_price = filters.NumberFilter(field_name="price", lookup_expr='gte')
    max_price = filters.NumberFilter(field_name="price", lookup_expr='lte')

    class Meta:
        model = Product
        fields = ['category', 'in_stock']  # 在Meta中指定過濾哪些欄位


class ProductList(generics.ListAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    filter_backends = (filters.DjangoFilterBackend,)
    filterset_class = ProductFilter   # 在filterset_class中,指定要使用的過濾類

由於支援雙下劃線語法,就可以在過濾類中建立區間過濾。比如ProductFilter中可以定義min_price和max_price,前端傳入最小价格和最大價格就可以過濾出相應欄位。

本文來自部落格園,作者:yyyz,轉載請註明原文連結:https://www.cnblogs.com/yyyzyyyz/p/15533452.html