00:00

文章目录

加载目录中...

DRF结合django-filter实现自定义过滤类

在 Django REST Framework (DRF) 中,结合 django-filter 可以实现强大的过滤功能,而自定义过滤类能满足更复杂的业务需求。以下是具体的使用方法:

一、准备工作

  1. 安装依赖首先安装 django-filter

    pip install django-filter
    
  2. 注册应用settings.py 中注册 django_filters

    INSTALLED_APPS = [
        # ...
        'django_filters',
    ]
    

二、基础使用:快速启用过滤

在 DRF 视图中直接使用 django-filter 提供的 DjangoFilterBackend,可快速实现基于模型字段的过滤。

示例模型

假设存在一个 Book 模型:

# models.py
from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=50)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publication_date = models.DateField()

视图中启用过滤

# views.py
from rest_framework import viewsets
from django_filters.rest_framework import DjangoFilterBackend
from .models import Book
from .serializers import BookSerializer

class BookViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    # 启用 django-filter 后端
    filter_backends = [DjangoFilterBackend]
    # 指定允许过滤的字段(精确匹配)
    filterset_fields = ['author', 'price']  # 支持 ?author=鲁迅&price=39.99

三、自定义过滤类:实现复杂过滤逻辑

当基础过滤无法满足需求(如范围查询、模糊匹配、跨字段关联等),可通过自定义过滤类实现。

步骤 1:定义自定义过滤类

继承 django_filters.FilterSet,并通过 Meta 类关联模型,同时定义自定义过滤字段。

# filters.py
import django_filters
from .models import Book

class BookFilter(django_filters.FilterSet):
    # 1. 模糊匹配(标题包含某个关键词)
    title_contains = django_filters.CharFilter(field_name='title', lookup_expr='icontains')
    # 2. 价格范围过滤(大于等于min_price,小于等于max_price)
    min_price = django_filters.NumberFilter(field_name='price', lookup_expr='gte')
    max_price = django_filters.NumberFilter(field_name='price', lookup_expr='lte')
    # 3. 日期范围(出版日期在某个区间)
    pub_date_after = django_filters.DateFilter(field_name='publication_date', lookup_expr='gte')
    # 4. 自定义方法过滤(例如:价格是否低于平均值)
    price_below_average = django_filters.BooleanFilter(method='filter_price_below_average')

    class Meta:
        model = Book
        # 额外支持的基础过滤字段(精确匹配)
        fields = ['author']  # 结合自定义字段,总过滤参数包括 author、title_contains 等

    # 实现自定义方法过滤
    def filter_price_below_average(self, queryset, name, value):
        if value:  # 当参数为 True 时生效
            avg_price = queryset.aggregate(avg=models.Avg('price'))['avg'] or 0
            return queryset.filter(price__lt=avg_price)
        return queryset
  • 核心参数说明
    • field_name:指定关联的模型字段。
    • lookup_expr:指定查询表达式(如 icontains 模糊匹配、gte 大于等于等,支持 Django ORM 所有查询表达式)。
    • method:自定义过滤方法(接收 querysetnamevalue 三个参数,返回处理后的查询集)。

步骤 2:在视图中应用自定义过滤类

在视图中通过 filterset_class 指定自定义过滤类,替代基础的 filterset_fields

# views.py
from rest_framework import viewsets
from django_filters.rest_framework import DjangoFilterBackend
from .models import Book
from .serializers import BookSerializer
from .filters import BookFilter  # 导入自定义过滤类

class BookViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends = [DjangoFilterBackend]
    # 应用自定义过滤类
    filterset_class = BookFilter

步骤 3:使用过滤参数

启动服务后,可通过 URL 参数调用过滤功能,例如:

  • 模糊查询标题包含 “Python” 的书籍:?title_contains=Python
  • 查询价格在 20 到 50 之间的书籍:?min_price=20&max_price=50
  • 查询 2023 年 1 月 1 日后出版的书籍:?pub_date_after=2023-01-01
  • 查询价格低于平均值的书籍:?price_below_average=true

四、高级技巧

  1. 结合搜索和排序可同时启用 DRF 的 SearchFilterOrderingFilter,与 DjangoFilterBackend 配合使用:

    from rest_framework.filters import SearchFilter, OrderingFilter
    
    class BookViewSet(viewsets.ReadOnlyModelViewSet):
        # ...
        filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
        search_fields = ['title', 'author']  # 支持全文搜索
        ordering_fields = ['price', 'publication_date']  # 支持排序
        ordering = ['-publication_date']  # 默认排序
    
  2. 动态过滤逻辑在自定义过滤类的 __init__ 方法中,可根据请求参数动态调整过滤规则(例如基于用户权限过滤)。

  3. 关联模型过滤支持通过双下划线 __ 关联外键字段,例如过滤某出版社的书籍:

    class BookFilter(django_filters.FilterSet):
        publisher_name = django_filters.CharFilter(field_name='publisher__name', lookup_expr='icontains')
    

通过自定义过滤类,django-filter 可以灵活满足各种复杂的过滤需求,结合 DRF 的视图集和序列化器,能快速构建强大的 API 过滤功能。

返回文章列表

评论区 0