一、手动编写配置文件
# 默认配置
# 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))