python測試開發django-169.過濾器django-filter 入門使用


前言

在管理后台查詢的時候,經常有需要查詢包含某個內容,按時間段查詢,或者商品價格大於多少,小於多少各種查詢條件。
django-filter 過濾器專門解決這種查詢的問題。

環境准備

使用pip安裝django-filter,目前安裝的版本v2.2.0

pip install django-filter

在setting.py添加django_filtersINSTALLED_APPS

INSTALLED_APPS = [
    ...
    'django_filters',
]

Django-filter 已針對所有支持的 Python 和Django版本以及最新版本的 Django REST Framework ( DRF ) 進行了測試。
python:3.5、3.6、3.7、3.8
django:2.2、3.0、3.1
DRF : 3.10+

簡單入門

Django-filter 提供了一種基於用戶提供的參數過濾查詢集的簡單方法。
假設我們有一個Product模型,我們想讓我們的用戶過濾他們在列表頁面上看到的產品。

先設計模型

class Manufacturer(models.Model):
    name = models.CharField(max_length=255)
    city = models.CharField(max_length=255)


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

過濾器設置,希望讓我們的用戶根據名稱、價格或發布日期進行過濾

  • exact 精准查找,等價於filter(name=xx),對應sql語句 where name='xx';
  • iexact 使用 like 進行查找, 對應sql語句where name like 'xx';

過濾器類似於 Django 的 ModelForm。參考之前的https://www.cnblogs.com/yoyoketang/p/15013472.html

import django_filters

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

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

以上為"價格"和"發布日期"字段生成"精確"查找。

寫個視圖

def product_list(request):
    f = ProductFilter(request.GET, queryset=Product.objects.all())
    return render(request, 'demo.html', {'filter': f})

template模板

<body>

    <form method="get">
        {{ filter.form.as_p }}
        <input type="submit" />
    </form>
    {% for obj in filter.qs %}
        {{ obj.name }} - ${{ obj.price }}<br />
    {% endfor %}

</body>

urls.py配置個訪問地址

url(r'^product$', views.product_list)

瀏覽器訪問

不輸入查詢內容,默認查詢全部,可以根據name/price/release_date查詢

該form屬性包含一個普通的 Django 表單,當我們遍歷 時,FilterSet.qs我們會得到結果查詢集中的對象。

FilterSet.qs查詢結果

FilterSet.qs 查詢的結果是 QuerySet 集合,可以轉成 json 格式

from django.forms.models import model_to_dict


def product_list(request):
    f = ProductFilter(request.GET, queryset=Product.objects.all())
    s = [model_to_dict(i) for i in f.qs]
    return JsonResponse({"code": 0, "msg": "success", "data": s})

查詢結果

{
	"code": 0,
	"msg": "success",
	"data": [{
		"id": 1,
		"name": "\u60a0\u60a0",
		"price": "22.23",
		"description": "aa",
		"release_date": "2021-11-08",
		"manufacturer": 1
	}, {
		"id": 2,
		"name": "yy",
		"price": "101.00",
		"description": "aa",
		"release_date": "2021-11-08",
		"manufacturer": 1
	}]
}

.qs過濾

要按request對象過濾主查詢集,只需覆蓋該 FilterSet.qs屬性。例如,您可以將博客文章過濾為僅發布的文章和登錄用戶擁有的文章)。

class ArticleFilter(django_filters.FilterSet):

    class Meta:
        model = Article
        fields = [...]

    @property
    def qs(self):
        parent = super().qs
        author = getattr(self.request, 'user', None)

        return parent.filter(is_published=True) \
            | parent.filter(author=author)

過濾相關查詢集 ModelChoiceFilter

ModelChoiceFilter和ModelMultipleChoiceFilter 支持可調用的行為。
如果傳遞了一個可調用對象,它將以 request 為唯一參數進行調用 。這允許您執行相同類型的基於請求的過濾,而無需求助於覆蓋 FilterSet.init.

def departments(request):
    if request is None:
        return Department.objects.none()

    company = request.user.company
    return company.department_set.all()

class EmployeeFilter(filters.FilterSet):
    department = filters.ModelChoiceFilter(queryset=departments)
    ...

自定義過濾字段 Filter.method

您可以通過指定 method 執行過濾來控制過濾器的行為。在方法參考中查看更多信息。請注意,您可以訪問過濾器集的屬性,例如 request.

class F(django_filters.FilterSet):
    username = CharFilter(method='my_custom_filter')

    class Meta:
        model = User
        fields = ['username']

    def my_custom_filter(self, queryset, name, value):
        return queryset.filter(**{
            name: value,
        })

聲明過濾器

聲明式語法在創建過濾器時為您提供了最大的靈活性,但它相當冗長。我們將使用下面的例子來勾勒核心過濾器參數上 FilterSet:

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

過濾器有兩個主要參數:

  • field_name:要過濾的模型字段的名稱。您可以使用 Django 的__語法遍歷“關系路徑”來過濾相關模型上的字段。例如:manufacturer__name。
  • lookup_expr:過濾時使用的字段查找。__ 可以再次使用Django 的語法來支持查找轉換。例如:year__gte。

字段field_name和字段一起lookup_expr代表一個完整的 Django 查找表達式。Django 的查找參考中提供了查找表達式的詳細說明。django-filter 支持包含轉換和最終查找的表達式。

使用 Meta.fields 生成過濾器

FilterSet Meta 類提供了一個fields屬性,可用於輕松指定多個過濾器,而無需大量代碼重復。基本語法支持多個字段名稱的列表:

import django_filters

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

以上為“價格”和“發布日期”字段生成“精確”查找。此外,字典可用於為每個字段指定多個查找表達式:

import django_filters

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

以上將生成 'price__lt'、'price__gt'、'release_date' 和 'release_date__year__gt' 過濾器。

過濾器查找類型“精確”是隱式默認值,因此永遠不會添加到過濾器名稱中。在上面的示例中,發布日期的確切過濾器是“release_date”,而不是“release_date__exact”。這可以被 FILTERS_DEFAULT_LOOKUP_EXPR 設置覆蓋。

類中fields序列中的項目Meta可能包括“關系路徑”,使用 Django 的__語法過濾相關模型上的字段:

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

覆蓋默認過濾器

像django.contrib.admin.ModelAdmin,它可以覆蓋默認的過濾器使用相同類型的所有車型領域 filter_overrides的Meta類:

class ProductFilter(django_filters.FilterSet):

    class Meta:
        model = Product
        fields = {
            'name': ['exact'],
            'release_date': ['isnull'],
        }
        filter_overrides = {
            models.CharField: {
                'filter_class': django_filters.CharFilter,
                'extra': lambda f: {
                    'lookup_expr': 'icontains',
                },
            },
            models.BooleanField: {
                'filter_class': django_filters.BooleanFilter,
                'extra': lambda f: {
                    'widget': forms.CheckboxInput,
                },
            },
        }

更多使用參考官方文檔https://django-filter.readthedocs.io/en/stable/guide/install.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM