rest framework之過濾組件


一、普通過濾

(一)get_queryset

  get_queryset方法是GenericAPIView提供的一個方法,旨在返回queryset數據集,而過濾就是要在這個方法返回數據集之前對數據進行篩選,然后返回篩選后的數據即可,那么也就是要求需要重寫這個方法:

    def get_queryset(self):
        """
        Get the list of items for this view.
        This must be an iterable, and may be a queryset.
        Defaults to using `self.queryset`.

        This method should always be used rather than accessing `self.queryset`
        directly, as `self.queryset` gets evaluated only once, and those results
        are cached for all subsequent requests.

        You may want to override this if you need to provide different
        querysets depending on the incoming request.

        (Eg. return a list of items that is specific to the user)
        """
        assert self.queryset is not None, (
            "'%s' should either include a `queryset` attribute, "
            "or override the `get_queryset()` method."
            % self.__class__.__name__
        )

        queryset = self.queryset
        if isinstance(queryset, QuerySet):
            # Ensure queryset is re-evaluated on each request.
            queryset = queryset.all()
        return queryset

源碼中的這個方法會從視圖配置中獲得queryset,然后判斷是否屬於QuerySet類型,如果屬於,就會返回這個queryset。

(二)實例

  • 請求API
class BookView(GenericViewSet):

    serializer_class = BookModelSerializer

    def get_queryset(self):
        queryset = models.Book.objects.all()
        title = self.request.query_params.get('title',None)
        if title is not None:
            queryset = models.Book.objects.filter(title=title).all()
        return queryset

    def list(self,request,*args,**kwargs):
        queryset= self.get_queryset()
        bs=self.get_serializer(queryset,many=True)
        return Response(bs.data)
  • 路由配置:

注意如果需要過濾,url中需要加入base_name屬性,並且base_name的值就是過濾參數的名稱:

router=routers.DefaultRouter()
router.register('books',views.BookView,base_name="title")
  • 生成的路由:
^books/$ [name='title-list']
^books\.(?P<format>[a-z0-9]+)/?$ [name='title-list']
  • 請求地址:
    http://127.0.0.1:8020/books/?title=語文

二、django-filter過濾

(一)django-filter的簡單使用

1、安裝django-filter

pip install django-filter

2、注冊django-filter

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
    'rest_framework',
    'django_filters',  #注冊django-filter
]

3、設置通用過濾后端

  • 全局配置
REST_FRAMEWORK = {

    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)

}
  • 局部視圖設置
import django_filters.rest_framework 

class BookView(GenericViewSet):

    queryset = models.Book.objects.all()
    serializer_class = BookModelSerializer
    filter_backends = (django_filters.rest_framework.DjangoFilterBackend,)

4、指定篩選字段

如果需求都是些簡單類型的篩選,那么可以在view或viewSet里面設置一個filter_fields屬性,列出所有依靠篩選的字段集合。

import django_filters.rest_framework
from rest_framework.viewsets import ModelViewSet

class BookView(ModelViewSet):

...    
    filter_fields = ('title',) #列出搜索字段
...

5、進行訪問

  • 路由配置
from rest_framework import routers
router=routers.DefaultRouter()
router.register('books',views.BookView) #無需base_name參數
urlpatterns = [
        re_path('',include(router.urls)),
]
  • 生成的路由
^books/$ [name='book-list']
^books\.(?P<format>[a-z0-9]+)/?$ [name='book-list']
^books/(?P<pk>[^/.]+)/$ [name='book-detail']
^books/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='book-detail']
  • 進行訪問
http://127.0.0.1:8020/books/?title=語文

(二)FilterSet的簡單使用

上面所搜索的字段是一對一的關系,沒有涉及到外鍵以及多對多字段,如果有外鍵或者多對多關系,可以在filter_fields中使用‘__’進行跨越:

class BookView(ModelViewSet):

    queryset = models.Book.objects.all()
    serializer_class = BookModelSerializer
    filter_backends = (django_filters.rest_framework.DjangoFilterBackend,)
    # 列出搜索字段,其中publish__name為ForeignKey字段,authors__name為ManyToMany字段
    filter_fields = ('title','publish__name','authors__name') 
class Book(models.Model):
    title=models.CharField(max_length=32)
    price=models.IntegerField()
    pub_date=models.DateField(null=True,blank=True)
    publish=models.ForeignKey("Publish",on_delete=models.CASCADE)
    authors=models.ManyToManyField("Author")
    def __str__(self):
        return self.title
models

此時請求地址:

 #含外鍵
http://127.0.0.1:8020/books/?title=語文&publish__name=北京出版社

#含多對多
http://127.0.0.1:8020/books/?title=語文&publish__name=北京出版社&authors__name=張三

但這樣外鍵和多對多將Django的雙下划線約定作為API的一部分暴露出來。如果想顯式地命名過濾器參數,可以顯式地將它包含在FilterSet類中:

1、定義FilterSet類

import django_filters
from app01 import models

class BookFilter(django_filters.rest_framework.FilterSet):
    publish = django_filters.CharFilter(field_name="publish__name")
    authors = django_filters.CharFilter(field_name="authors__name")
    class Meta:
        model = models.Book
        fields = ['title', 'publish', 'authors']

2、在視圖中使用定義的FilterSet類

class BookView(ModelViewSet):

    queryset = models.Book.objects.all()
    serializer_class = BookModelSerializer
    filter_backends = (django_filters.rest_framework.DjangoFilterBackend,)
    filter_class = BookFilter #使用定義的FilterSet類

此時請求地址:

http://127.0.0.1:8020/books/?title=語文&publish=北京出版社&authors=張三

3、總結

FilterSet可以實現較為復雜的過濾功能,如果是普通字段可以使用filter_fields 添加字段進行過濾,如果有外鍵、多對多以及范圍(日期范圍、價格范圍)使用FilterSet.

三、其它過濾

(一)搜索過濾(SearchFilter)

支持基於簡單查詢參數的搜索,並且基於Django admin的搜索功能。

  • 設置過濾后端
from rest_framework import filters

class BookView(ModelViewSet):

...
    filter_backends = (filters.SearchFilter,)
...
  • 設置查詢字段
from rest_framework import filters

class BookView(ModelViewSet):

    queryset = models.Book.objects.all()
    serializer_class = BookModelSerializer
    # filter_backends = (django_filters.rest_framework.DjangoFilterBackend,)
    filter_backends = (filters.SearchFilter,)

   #凡是以下字段內容都會被搜到
    search_fields = ('title','publish__name','authors__name')

當然可以通過在search_fields 前面添加各種字符來限制搜索行為:

'^' 以指定內容開始.

'=' 完全匹配

'@' 全文搜索(目前只支持Django的MySQL后端)

'$' 正則搜索

例如:

search_fields = ('=title',)
  • 客戶端訪問
#將北京出版社的內容全部搜索出來
http://127.0.0.1:8020/books/?search=北京出版社
#將張三相關內容搜索出來
http://127.0.0.1:8020/books/?search=張三

通過關鍵詞search進行搜索,可以搜索后端search_fields提供字段的內容。

SearchFilters類的默認搜索關鍵字為search,可以通過SEARCH_PARAM進行覆蓋設置

class BookView(ModelViewSet):
...
    SEARCH_PARAM = 'ss'
...

(二)排序篩選(OrderingFilter)

  • 設置排序篩選后端
from rest_framework import filters

class BookView(ModelViewSet):

...
    filter_backends = (filters.OrderingFilter,)
...
  • 指定支持排序的字段(ordering_fields )
from rest_framework import filters

class BookView(ModelViewSet):
...
    filter_backends = (OrderingFilter,)
    ordering_fields = ('title', 'id') #指定支持排序的字段
...
  • 客戶端訪問

通過關鍵字ordering請求返回的數據按照什么排序

#按照title排序
http://127.0.0.1:8020/books/?ordering=title

#按照id排序
http://127.0.0.1:8020/books/?ordering=id
#按照id逆序
http://127.0.0.1:8020/books/?ordering=-id

#按照多個字段排序
http://127.0.0.1:8020/books/?ordering=id,title
  • 默認排序

如果需要在返回的數據中已經排好序了,可以在視圖中使用ordering參數:

from rest_framework import filters

class BookView(ModelViewSet):

    queryset = models.Book.objects.all()
    serializer_class = BookModelSerializer
    filter_backends = (filters.OrderingFilter,)
    ordering_fields = ('title', 'id')
    ordering=('-id',) #默認排序

客戶端訪問:

    http://127.0.0.1:8020/books/

返回的是已經按照id逆序排列的數據。

參考文檔:https://q1mi.github.io/Django-REST-framework-documentation/api-guide/filtering_zh/#filtering

 


免責聲明!

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



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