DRF--GenericAPIView及其搜索,排序,分页功能,分页功能定制

GenericAPIView具备的方法和类属性:

        类属性: queryset, serializer_class

        方法: get_queryset,

                get_serializer,  get_serialzier_class,

                filter_queryset,

                paginate_queryset,  get_paginated_response  

1.GenericAPIView

        1.1 具备View的所有特性

        1.2 具备APIView中的认证,授权,限流功能

        1.3 支持对于获取列表数据接口的搜索,排序,分页功能

        1.4 一旦继承了GenericAPIView,往往需要指定queryset,serializer_class类属性

                1.4.1 queryset指定的是:当前类视图的内部的实例方法会使用的查询集对象

                1..4.2 serializer指定的是:当前类视图的内部的实例方法会用到的序列化器类

        1.5 实例方法中,此处调用GenericAPIView中的get_queryset()方法获取查询集对象,不直接使

                用self.queryset,是因为后期我们可能重写get_queryset()方法来满足我们的需求,如果未

                重写get_queryset()方法,就必须指定queryset类属性.

                        ps:以下示例属于未重写get_queryset()方法

        1.6 实例方法中,此处调用GenericAPIView中的get_serializer()方法获取序列化器类, 一般不

                直接使用self.serializer_class类属性,是因为后期我们可能重写get_serializer()方法来满

                足我们的需求,如果未重写get_serializer()方法,就必须指定serializer_class类属性

                          ps:以上示例属于未重写get_serializer() 方法

2. 自定义路径参数,不使用pk

        2.1 GenericAPIView中定义了类属性lookup_field = 'pk' 和 lookup_url_kwarg = None,

         如果我们在类视图中继承了GenericAPIView,就可以重写类属性lookup_url_kwarg=自定义值

        2.2 自定义值为lookup_url_kwarg = sb 以后,路径参数重我们就要使用sb

3.GenericAPIView的搜索过滤

        在继承了GenericAPIView的类视图中,search_fields类属性用于指定模型类中需要进行搜索过滤的字段名.

        使用icontains查询类型作为过滤类型.

        可以使在字段前加相应符号,指定查询类型

                如:

        3.1 在全局配置文件settings.py文件中定义DEFAULT_FILTER_BACKENDS

        3.2 在查询时需要使用过滤的类视图中指定 search_fields = ['字段1', '字段2'.......]

        3.3 在查询实例方法get()中调用GenericAPIView的过滤方法filter_queryset(),

                对查询集进行过滤,并返回过滤后的查询集 

         3.4 前端搜索查询

        3.5 若自定义了了搜索参数,则需使用自定义搜索参数过滤

                3.6 也可以在类视图中指定过滤引擎,优先级>全局配置

4.GenericAPIView的排序

        a).ordering_fields类属性指定模型类中允许前端进行排序的字段名称.

        b).前端默认可以使用ordering作为排序功能查询字符串参数名称,默认为该字段的生序.

        c).如果字段前面添加‘-’,代表该字段降序.

        d).如果指定多个字段,用英文‘,’ 分隔.

        4.1 在全局配置文件settings.py指定排序引擎

         4.2 在需要排序操作的类视图中指定需要排序的字段ordering_fields = ['字段1', '字段2']

         4.3 前端访问

5.GenericAPIView的分页功能

        5.1 在全局配置文件settings.py指定分页引擎 DEFAULT_PAGINATION_CLASS,PAGE_SIZE

        5.2 在类视图中调用GenericAPIView的分页方法paginate_queryset(queryset=queryset),

                返回GenericAPIView中分页特有的response:       

                        return self.get_paginated_response(serializer.data)

        5.3 输出每页跟settings.py中配置的PAGE_SIZE条数据

6. GenericAPIView中的特有过滤,排序,分页方法总结:

        1.在全局配置文件setting.py中指定和rest_framework/settings.py文件中一样的配置信息.

        2.在类视图中定义过滤search_fields,ordering_fields类属性.

        3.在类实例方法中引用GenericAPIView一些特有的方法,如:

                3.1 self.filter_queryset(queryset=queryset)

                3.2 self.paginate_queryset(queryset=queryset)

                      return self.get_paginated_response(serializer.data)

7. 附代码

        # settings.py

"""
Django settings for test_platform project.

Generated by 'django-admin startproject' using Django 4.0.4.

For more information on this file, see
https://docs.djangoproject.com/en/4.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.0/ref/settings/
"""

from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-e8n&hal3misgqk2rs*@%=ii#h)cj7_01f2(q(czi_4zf=b+%26'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'rest_framework',

    # 注册子应用
    'projects',
    'interfaces'
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'test_platform.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'test_platform.wsgi.application'


# Database
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases

DATABASES = {
    # 'default': {
    #     'ENGINE': 'django.db.backends.sqlite3',
    #     'NAME': BASE_DIR / 'db.sqlite3',
    # }

    'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'eyes_db',
            'HOST': '127.0.0.1',
            'USER': 'root',
            'PASSWORD': '123456',
            'PORT': '3306',

        }

}


# Password validation
# https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/4.0/topics/i18n/

LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.0/howto/static-files/

STATIC_URL = 'static/'

# Default primary key field type
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

# 指定drf中能用的各种解析器,渲染器,过滤引擎,搜索引擎,排序引擎,分页引擎等
REST_FRAMEWORK = {
    # 指定全局渲染引擎
    'DEFAULT_RENDERER_CLASSES': [
        # 此渲染引擎,可以向前端返回json格式数据
        'rest_framework.renderers.JSONRenderer',
        # 可以向前端返回可浏览的API页面文档
        'rest_framework.renderers.BrowsableAPIRenderer',
    ],

    # 指定全局解析引擎
    'DEFAULT_PARSER_CLASSES': [
        # 解析前端传来的Json格式数据,若前端指定content-type=application/json,
        # 就会使用此JSONParser解析器解析
        'rest_framework.parsers.JSONParser',
        # 解析前端传来的表单格式数据,若前端指定content-type=application/x-www-form-urlencoded,
        # 就会使用此FormParser解析器解析
        'rest_framework.parsers.FormParser',
        # 解析前端传来的multipart-form-data格式数据,若前端指定content-type=multipart/form-data,
        # 就会使用此MultiPartParser解析器解析
        'rest_framework.parsers.MultiPartParser'
    ],

    #1。 在全局'DEFAULT_FILTER_BACKENDS'指定使用的过滤引擎类(SearchFilter为搜索引擎类)
    'DEFAULT_FILTER_BACKENDS': [
                                'rest_framework.filters.SearchFilter',
                                # 排序引擎(OrderingFilter为排序引擎类)
                                'rest_framework.filters.OrderingFilter',
                                ],
    # 可以在全局使用SEARCH_PARAM修改起前端过滤查询字符串参数名称(默认为search)
    'SEARCH_PARAM': 'se',

    # 指定分页引擎
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    # 指定每页条数
    'PAGE_SIZE': 2,
}



if __name__ == '__main__':
    BASE_DIR = Path(__file__).resolve()
    print('111',BASE_DIR)

        # projects/views.py

import json

from django.http import HttpResponse, JsonResponse

# 子应用视图
from django.views import View
from rest_framework import status, filters
from rest_framework.filters import OrderingFilter
from rest_framework.generics import GenericAPIView
from rest_framework.renderers import JSONRenderer
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.views import APIView



from projects.models import Projects
# from projects.serializers import ProjectSerializer
from projects.serializers import PorjectModelSerializer
from utils.pagination import PageNumberPagination

class JsonDecoderError111(BaseException):
    """
    1.serializers.ModelSerializer提供模型对象序列化+create()方法+update()方法
    2。APIView 提供从request.data中获取请求参数+返回Response()对象
    """
    pass


# class ProjectsView(View):
# class ProjectsView(APIView):
class ProjectsView(GenericAPIView):
    """
    继承GenericAPIView(或者其子类)的类视图
    1。具备View的所有特性
    2。具备APIView中的认证,授权,限流功能
    3。支持对于获取列表数据接口的搜索,排序,分页功能
    """
    queryset = Projects.objects.all()
    serializer_class = PorjectModelSerializer

    # filter_backends在继承了GenericAPIView的类视图中指定过滤引擎,优先级>全局配置
    # filter_backends = [filters.SearchFilter, OrderingFilter]
    # 2。 类视图中指定可用于过滤查询的字段search_fields = [xxx]
    search_fields = ['^full_name', 'id']

    # 配置过滤器类
    filter_backends = [filters.SearchFilter, OrderingFilter]
    # 排序字段
    ordering_fields = ['full_name', 'leader', 'id']
    # 指定自定义的分页器引擎(先导入)
    pagination_class = PageNumberPagination

    def get(self, request: Request):
        # 查询所有项目信息
        # 实例方法中,此处调用GenericAPIView中的get_queryset()方法获取查询集对象,
        # 不直接使用self.queryset,是因为后期我们可能重写get_queryset()方法来满足我们的需求,
        # 如果未重写get_queryset()方法,就必须指定queryset类属性
        # queryset = self.get_queryset()

        # 3。 此处filter.queryset,可以对查询集再过滤,返回过滤后的查询集
        queryset = self.filter_queryset(queryset=self.get_queryset())

        # 调用GenericAPIView的分页方法paginate_queryset(),参数为上面过滤后的查询集
        page_queryset = self.paginate_queryset(queryset=queryset)
        if page_queryset is not None:
            # 若分页成功,返回分页处理后的Response
            serializer = self.get_serializer(instance=page_queryset, many=True)
            return self.get_paginated_response(serializer.data)

        # 实例方法中,此处调用GenericAPIView中的get_serializer()方法获取序列化器类,
        # 一般不直接使用self.serializer_class类属性,是因为后期我们可能重写get_serializer()方法来满足我们的需求,
        # 如果未重写get_serializer()方法,就必须指定serializer_class类属性
        serializer = self.get_serializer(instance=queryset, many=True)

        return Response(serializer.data, status=status.HTTP_200_OK)

    def post(self, request: Request):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        return Response(serializer.data, status=status.HTTP_201_CREATED)


class ProjectDetailView(GenericAPIView):
    get_pro_obj = Projects.objects.get
    serializer_class = PorjectModelSerializer

    # 自定义lookup_field 值
    lookup_url_kwarg = 'sb'

    # def get(self, request, pk):
    def get(self, request, *args, **kwargs):
        # GenericAPIView提供的get_object()方法不需要传pk
        instance = self.get_object()
        serializer = self.get_serializer(instance=instance)

        return Response(serializer.data, status=status.HTTP_200_OK)

    def put(self, request: Request, *args, **kwargs):
        # 获取待更新的对象
        instance = self.get_object()
        serializer = self.get_serializer(instance=instance, data=request.data)

        serializer.is_valid(raise_exception=True)
        serializer.save()

        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def delete(self, request: Request, *args, **kwargs):
        instance = self.get_object()
        count = instance.delete()
        result = {
            'msg': f'删除{args}成功',
            'count': count,
        }
        return Response(data=result, status=204)

8.分页功能定制

        8.1 drf的rest_framework.pagination.PageNumberPagination分页类源码:

                默认只定义了页码的参数"page",没有定义每页条数参数,默认为None,我们可以对其进行二次开发,修改None为自己想要的查询字符串参数

        8.2  utils中定义pagination.py文件

        8.3 自定义分页控制类

                8.3.1 继承drf的分页控制类

"""
自定义分页器类
"""
from django.utils.translation import gettext_lazy as _
from rest_framework.pagination import PageNumberPagination as _PageNumberPagination


class PageNumberPagination(_PageNumberPagination):
    
    # 每页条数
    page_size = 3
    
    # 前端指定页码时可使用的查询字符串参数
    page_query_param = 'page'
    page_query_description = _('获取的页码.')

    # 前端指定每页数据条数时可使用的查询字符串参数
    page_size_query_param = 'size'
    page_size_query_description = _('每一页数据条数.')

    # 每页最大数据条数
    max_page_size = 50

    last_page_strings = ('last',)

    template = 'rest_framework/pagination/numbers.html'
    
    # 超过数据量时的提示
    invalid_page_message = _('无效页码.')

                8.3.2 全局配置文件中使用自定义的分页器类,不用drf的

                8.3.3 在需要使用自定义分页器的类视图中使用自定义分页器,优先级>全局

                8.3.4 前端输出:

                 8.3.5 自定义返回内容的字段

                        源码:

                由上可知,我们前端收到的返回,受

                rest_framework.pagination.PageNumberPagination.get_paginated_response()方法

                控制,里面定义了给我买返回count,next,previous,results字段,所以我们需要添加返回内容

                的话,就要重写该方法.

         输出

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chuntian_tester

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值