DAY102 - Rest Framework(七)- 手动编写配置文件、分页器和版本控制

DRF配置与分页详解
本文详细介绍了Django Rest Framework(DRF)的配置过程,包括如何手动编写配置文件,以及DRF中三种分页器的使用方法:普通分页器、偏移分页器和加密分页器。此外,还探讨了DRF中的版本控制实现。

一、手动编写配置文件

# 默认配置
# conf-->global_setting.py
DEBUG = None

TIME_ZONE = 'America/Chicago'

USE_TZ = False


# 用户配置
# usersetting-->setting.py
DEBUG = True

TIME_ZONE = 'Asia/Shanghai'

USE_TZ = False

ABC='123'
# conf-->__init__.py
from conf import global_setting
import os
import importlib


class MySetting():
    # dir:返回模块的属性列表
    def __init__(self):

        settings_module = os.environ.get('USER_SETTING')
        # 通过环境变量,获得用户配置的文件路径(字符串)
        # settings_module = 'usersetting.setting'
        
        # 循环获得默认配置的值
        for setting in dir(global_setting):
            if setting.isupper():
                setattr(self, setting, getattr(global_setting, setting))
        
        # 使用importlib.import_module()获得用户配置的路径
        mod = importlib.import_module(settings_module)
        
        # 循环获得用户配置的值,会覆盖默认配置
        for setting in dir(mod):
            if setting.isupper():
                setattr(self, setting, getattr(mod, setting))


setting = MySetting()
# 运行文件
import os

os.environ.setdefault('USER_SETTING', 'usersetting.setting')

from conf import setting
print(setting.DEBUG)

二、分页器

1.普通分页

基本使用

# 普通分页
from rest_framework.pagination import PageNumberPagination

class Books(APIView):
    def get(self, request):
        books = models.Book.objects.all()
        # 生成一个PageNumberPagination对象
        page = PageNumberPagination()
        # 第一个参数:要分页的数据,第二个参数request对象,第三个参数,当前视图对象
        # 在数据库中获取分页的数据
        page_list = page.paginate_queryset(books, request, self)
        ret = BooksSerializer(instance=page_list, many=True)
        print(ret.data)
        return Response(ret.data)
    
        # 这个也是返回Response对象,但是比基本的多了上一页,下一页,和总数据条数(了解即可)
        # return page.get_paginated_response(ret.data)
# setting.py
# 配置每页显示数
REST_FRAMEWORK = {
    # 每页显示两条
    'PAGE_SIZE': 2
}

配置属性

# 方法一:自定义分页类继承PageNumberPagination

class MyPageNumberPagination(PageNumberPagination):
    # 每页显示的数据数,默认去setting里找
    page_size = 3
    
    # 配置GET里接收的key:value形式的key值,可以指定当前页
    # http://127.0.0.1:8000/books/?p=2
    # 默认为page
    page_query_param = 'p'
    
    # 可以通过URL的方式指定每页显示的数据数
    # http://127.0.0.1:8000/books/?page=2&size=1
    # 默认为size
    page_size_query_param='s'
    
    # 每页最多显示数据数
    max_page_size = 4


class Books(APIView):
    def get(self, request):
        books = models.Book.objects.all()
        # 生成一个自定义的对象
        page = MyPageNumberPagination()
        page_list = page.paginate_queryset(books, request, self)
        ret = BooksSerializer(instance=page_list, many=True)
        print(ret.data)
        return Response(ret.data)
# 方式二:视图里设置属性
class Books(APIView):
    def get(self, request):
        books = models.Book.objects.all()
        page = PageNumberPagination()
        page.page_size = 3
        page.page_query_param = 'page'
        page.page_size_query_param = 'size'
        page.max_page_size = 4
        page_list = page.paginate_queryset(books, request, self)
        ret = BooksSerializer(instance=page_list, many=True)
        print(ret.data)
        return Response(ret.data)

2.偏移分页

基本使用

# 偏移分页
from rest_framework.pagination import LimitOffsetPagination

class Books(APIView):
    def get(self, request):
        books = models.Book.objects.all()
        # 生成一个LimitOffsetPagination对象
        page = LimitOffsetPagination()
        # 第一个参数:要分页的数据,第二个参数request对象,第三个参数,当前视图对象
        # 在数据库中获取分页的数据
        page_list = page.paginate_queryset(books, request, self)
        ret = BooksSerializer(instance=page_list, many=True)
        print(ret.data)
        return Response(ret.data)
    
        # 这个也是返回Response对象,但是比基本的多了上一页,下一页,和总数据条数(了解即可)
        # return page.get_paginated_response(ret.data)
# setting.py
# 配置每页显示数
REST_FRAMEWORK = {
    # 每页显示两条
    'default_limit':2
}

配置属性

# 配置属性的两种方法与普通分页一样
# 每页显示的条数
default_limit = api_settings.PAGE_SIZE

# 标杆值
# 配置GET里接收的key:value形式的key值,可以指定标杆值
# 一般和limit_query_param一起使用
# 默认为offset,可以自定义
offset_query_param = 'offset'

# 可以通过URL的方式指定每页显示的数据数
# http://127.0.0.1:8000/books/?offset=4&limit=3
# 从第四条数据(不包括)开始取三条数据
# 如果写了limit=3,会覆盖default_limit的数据数
# 默认为limit,可以自定义
limit_query_param = 'limit'

# 每页显示最大的条数
# 如果写了limit的值>max_limit的值,以max_limit为准
max_limit = None

3.加密分页

基本使用

# 加密分页
from rest_framework.pagination import CursorPagination

class Books(APIView):
    def get(self, request):
        books = models.Book.objects.all()
        # 生成一个PageNumberPagination对象
        page = CursorPagination()
        # 先把数据按照ordering排序,再从数据库取出来
        page.ordering = 'id'
        
        page_list = page.paginate_queryset(books, request, self)
        ret = BooksSerializer(instance=page_list, many=True)
        return Response(ret.data)
        # page.get_paginated_response()会返回链接和总的数据数
        # return page.get_paginated_response(ret.data)
# setting.py
# 配置每页显示数
REST_FRAMEWORK = {
    # 每页显示两条
    'PAGE_SIZE': 2,
}

配置属性

# 配置属性的两种方法与普通分页一样'
# 每页显示的条数
page_size = api_settings.PAGE_SIZE

# 在URL显示加密后的页码
# http://127.0.0.1:8000/books/?cursor=cD0y
# 默认为cursor,可以自定义
cursor_query_param = 'cursor

# 数据按照ordering排序,默认是'-created'
ordering = '-created'

# 每页最多显示数据数
max_page_size = 4

三、版本控制

基于restful规范,应当由版本之分,rest-framework给我们提供了一个

from rest_framework.versioning import QueryParameterVersioning,AcceptHeaderVersioning,NamespaceVersioning,URLPathVersioning

# 基于url的get传参方式:
#  QueryParameterVersioning------>如:/users?version=v1

# 基于url的正则方式:
#  URLPathVersioning------>/v1/users/

# 基于 accept 请求头方式:
#  AcceptHeaderVersioning------>Accept: application/json; version=1.0

# 基于主机名方法:
#  HostNameVersioning------>v1.example.com

# 基于django路由系统的namespace:
#  NamespaceVersioning------>example.com/v1/users/

基本使用

# 路由
url(r'^(?P<version>[v1|v2|v3]+)/books/', views.Books.as_view()),
from rest_framework.versioning import URLPathVersioning


class Books(APIView):
    # 局部使用
    versioning_class = URLPathVersioning

    def get(self, request,*args,**kwargs):
        books = models.Book.objects.all()
        # 获得版本号
        print(request.version)
        # URLPathVersioning对象
        print(request.versioning_scheme)
        
        ret = BooksSerializer(books, many=True)
        return Response(ret.data)
    
#全局使用
REST_FRAMEWORK = {
    'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning',
    'DEFAULT_VERSION': 'v1',            # 默认版本(从request对象里取不到,显示的默认值)
    'ALLOWED_VERSIONS': ['v1', 'v2'],   # 允许的版本
    'VERSION_PARAM': 'version'          # URL中获取值的key
}

反向解析

# url
url(r'^(?P<version>[v1|v2|v3]+)/books/', views.Books.as_view(),name='test'),


# 反向生成URL
# 第一个参数是路由名,第二个是request
reverse_url = request.versioning_scheme.reverse('test', request=request)
print(reverse_url)
# http://127.0.0.1:8000/v1/books/

源码解析

# 第一步
# dispatch()
def dispatch(self, request, *args, **kwargs):
    
    ........
    # 由此进入下一步
    self.initial(request, *args, **kwargs)
    
    ........
    
# 第二步
# initial()
def initial(self, request, *args, **kwargs):

    ........
    # 把determine_version方法的返回值解压赋值给version和scheme
    # 也就是version = 版本号
    # scheme = 版本类对象
    version, scheme = self.determine_version(request, *args, **kwargs)
    # 再把version和scheme分别赋值给request
    request.version, request.versioning_scheme = version, scheme
    
    ........
    
# 第三步
# self.determine_version()
def determine_version(self, request, *args, **kwargs):
    
    # 如果versioning_class is None,返回空元组
    if self.versioning_class is None:
        return (None, None)
    
    # 如果有,就加上()执行
    # 从视图里找,有:versioning_class = URLPathVersioning
    # scheme = URLPathVersioning()
    # 也就是说scheme是URLPathVersioning实例化后的对象
    scheme = self.versioning_class()
    
    # 返回元组(scheme.determine_version(request, *args, **kwargs),scheme)
    # scheme.determine_version(),是在URLPathVersioning里的方法
    return (scheme.determine_version(request, *args, **kwargs), scheme)
# 第四步
# URLPathVersioning ---> determine_version
def determine_version(self, request, *args, **kwargs):
    # version_param和default_version都会从setting里找
    # version_param='version'
    # default_version='v1'
    # 假设url: http://127.0.0.1:8000/v2/books/
    # 从参数里找url传进来的version,也就是v2,没有就默认值self.default_version
    version = kwargs.get(self.version_param, self.default_version)
    
    # is_allowed_version,从下往上找,都没有,在父类BaseVersioning里
    # 也就是说,如果返回True,就直接把接收到的version返回,false则抛异常
    if not self.is_allowed_version(version):
        raise exceptions.NotFound(self.invalid_version_message)
    return version


# BaseVersioning ---> is_allowed_version()
def is_allowed_version(self, version):
    # 如果视图里没有,会从setting里找,还没有,就去默认里找,默认里是None,就返回True
    # 也就是说,如果setting里写了但为空,或者没写,就返回True
    if not self.allowed_versions:
        return True
    
    # 只要version为空并且version不在allowed_versions范围内
    # 或者version不等于默认值default_version并且version不在allowed_versions范围内
    # 就会返回false
    return ((version is not None and version == self.default_version) or(version in self.allowed_versions))

转载于:https://www.cnblogs.com/xvchengqi/p/10139251.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值