django rest framework- filtering, searching, sorting

Filter DjangoFilterBackend:

DRF generic list view returns by default the entire querysetquery result, but usually only required part of the business, in which case you need to use the "filters" to limit the returned result set.
The most stupid way is to inherit GenericAPIViewclass or inherited GenericAPIViewclass and override the .get_queryset()method, we first look at the Class View to add a methodget_queryset

from rest_framework import generics
class ArticleViewSet(generics.ListAPIView):
    queryset = Article.objects.all()  # 查询结果集
    serializer_class = ArticleSerializer # 序列化类
    pagination_class = ArticlePagination   # 自定义分页会覆盖settings全局配置的

    def get_queryset(self):
        queryset = Article.objects.all()
        read_num = self.request.query_params.get('read_num', 0)  # 获取查询字段值
        if read_num:
            queryset = queryset.filter(read_num__gt=int(read_num))

        return queryset
Test results
  1. When the transfer read_num=83method according to get_querysetthe determination condition is greater than the find 83are 3records.
    9286065-736acc5e5d03e4e7.png
    image.png
  2. We try again if you do not pass, recorded seven records found.
    9286065-1b86548d132bb2e8.png
    image.png
summary

We rewrite the above get_querysetmethod to achieve the filtering effect, if to do so in a complex filter conditions, the code would be too redundant, and it is possible to achieve most of the code have been repeating similar function in their daily operations, we need to Gets the specified condition data, for example, the article, we need to specify the classification, Views, and other Chan-point number. Sometimes we need to be sorted in accordance with Views. These require us to do more to expand ArticleViewSet.

django-filter module

django-filterLibrary includes a DjangoFilterBackendclass that supports RESThighly customizable framework in the field of filtration.
First installationdjango-filter

pip install django-filter

Then django_filtersadd to Djangothe INSTALLED_APPS.

REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}

Or applied to a single filter or ViewSet View (for general use such ):

from rest_framework import viewsets
from django_filters.rest_framework import DjangoFilterBackend

class ArticleViewSet(mixins.ListModelMixin, mixins.CreateModelMixin, viewsets.GenericViewSet):
    queryset = Article.objects.all()  # 查询结果集
    serializer_class = ArticleSerializer # 序列化类
    pagination_class = ArticlePagination   # 自定义分页会覆盖settings全局配置的
    # 过滤器
    filter_backends = (DjangoFilterBackend,)
    # 如果要允许对某些字段进行过滤,可以使用filter_fields属性。
    filter_fields = ('title', 'category')

    # def get_queryset(self):
    #     queryset = Article.objects.all()
    #     read_num = self.request.query_params.get('read_num', 0)
    #
    #     if read_num:
    #         queryset = queryset.filter(read_num__gt=int(read_num))
    #
    #     return queryset
Test results

9286065-f3fe3d0eea1218e5.png
image.png

As can be seen by adding the corresponding add filter and the filter related fields, note that this is an exact match between fields and a relationship, if a is empty, in other matches, such as title=测试&category= is according title to pinpoint.

Custom filter class

According to the default matching precision, if you want to achieve a fuzzy search can be custom filter class, then filtered filter_class designated collections.
New filter filefilters.py

from django_filters import rest_framework
from article.models import Article

class AriticleFilter(rest_framework.FilterSet):
    min_read = rest_framework.NumberFilter(field_name='read_num', lookup_expr='gte')
    max_read = rest_framework.NumberFilter(field_name='read_num', lookup_expr='lte')
    title = rest_framework.CharFilter(field_name='title', lookup_expr='icontains')

    class Meta:
        model = Article
        fields = ['title', 'category', 'min_read', 'max_read']

Modify the view class

from rest_framework import viewsets
from django_filters.rest_framework import DjangoFilterBackend
from .filters import AriticleFilter

class ArticleViewSet(mixins.ListModelMixin, mixins.CreateModelMixin, viewsets.GenericViewSet):
    queryset = Article.objects.all()  # 查询结果集
    serializer_class = ArticleSerializer # 序列化类
    pagination_class = ArticlePagination   # 自定义分页会覆盖settings全局配置的
    # 过滤器
    filter_backends = (DjangoFilterBackend,)
    # 如果要允许对某些字段进行过滤,可以使用filter_fields属性。
    #filter_fields = ('title', 'category')
    # 使用自定义过滤器
    filter_class = AriticleFilter

    # def get_queryset(self):
    #     queryset = Article.objects.all()
    #     read_num = self.request.query_params.get('read_num', 0)
    #
    #     if read_num:
    #         queryset = queryset.filter(read_num__gt=int(read_num))
    #
    #     return queryset

Test results:


9286065-8f3b41c5851b014e.png
image.png

Search SearchFilter

If you want to explicitly specify which fields can be searched, you can use search_fields property defaults can serializer_classbe read in any search field on the properties of the specified serializer:


from rest_framework import viewsets
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import filters

from .filters import AriticleFilter

class ArticleViewSet(mixins.ListModelMixin, mixins.CreateModelMixin, viewsets.GenericViewSet):
    queryset = Article.objects.all()  # 查询结果集
    serializer_class = ArticleSerializer # 序列化类
    pagination_class = ArticlePagination   # 自定义分页会覆盖settings全局配置的
    # 过滤器
    filter_backends = (DjangoFilterBackend,filters.SearchFilter,)
    # 如果要允许对某些字段进行过滤,可以使用filter_fields属性。
    #filter_fields = ('title', 'category')
    # 使用自定义过滤器
    filter_class = AriticleFilter
    search_fields = ('title', 'description', 'content')

As it can be seen more than a search box


9286065-90ec367f96a35b54.png
image.png

By default, the search will use the case-insensitive partial match. Search parameters can contain multiple search terms, they should be spaces and / or commas. If you use multiple search terms, only when all the terms provided matches, will return to the object in the list. By default, the search parameter is named "search", but this may be overwritten SEARCH_PARAM set.
The search behavior may be restricted by prepending various characters to the search_fields.
You can limit your search behavior by adding some characters in search_fields as follows:
'^': to start the search string xx
'=': exact match
'@': full text Search (currently only supports MySQL backend Django's)
'$': regular expression search
as: search_fields = ( '@username', '= email')

Sequence

OrderingFilter class field support for a single query result set to be sorted.
By default, the query parameter is named "ordering", but this may be overwritten ORDERING_PARAM set.
You can use ordering_fields property explicitly specify which fields can perform sort, which helps prevent accidental data leakage, such as allowing users to password hash fields or other sensitive data is sorted.
If no ordering_fields the property is filtered on any readable field can serializer_class serializer attribute specified.


from rest_framework import viewsets
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import filters
from .filters import AriticleFilter

class ArticleViewSet(mixins.ListModelMixin, mixins.CreateModelMixin, viewsets.GenericViewSet):
    queryset = Article.objects.all()  # 查询结果集
    serializer_class = ArticleSerializer # 序列化类
    pagination_class = ArticlePagination   # 自定义分页会覆盖settings全局配置的
    # 过滤器 过滤,搜索,排序
    filter_backends = (DjangoFilterBackend,filters.SearchFilter,filters.OrderingFilter)
    # 如果要允许对某些字段进行过滤,可以使用filter_fields属性。
    #filter_fields = ('title', 'category')
    # 使用自定义过滤器
    filter_class = AriticleFilter
    # 搜索
    search_fields = ('title', 'description', 'content')
    # 排序
    ordering_fields = ('id', 'read_num')

effect:


9286065-cb5c0d9e92cfa2a6.png
image.png

Reproduced in: https: //www.jianshu.com/p/292a06275712

Guess you like

Origin blog.csdn.net/weixin_34111790/article/details/91315520