DAY102 - Rest Framework(七)- 手動編寫配置檔案、分頁器和版本控制
阿新 • • 發佈:2018-12-18
一、手動編寫配置檔案
# 預設配置
# 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/?page=2 page_query_param = 'page' # 可以通過URL的方式指定每頁顯示的資料數 # http://127.0.0.1:8000/books/?page=2&size=1 page_size_query_param='size' # 每頁最多顯示資料數 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_query_param = 'offset'
# 可以通過URL的方式指定每頁顯示的資料數
# http://127.0.0.1:8000/books/?offset=4&limit=3
# 從第四條資料(不包括)開始取三條資料
# 如果寫了limit=3,會覆蓋default_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_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))