RESTFULL 07 rest-framework分頁器,相應器,解析器,url控制器,版本控制
rest-framework分頁器,相應器,解析器,url控制器,版本控制
一、分頁器
1、簡單分頁(查看第n頁,每頁顯示n條)
from rest_framework.pagination import PageNumberPagination # 一 基本使用:url=url=http://127.0.0.1:8000/pager/?page=2&size=3,size無效 class Pager(APIView): def get(self,request,*args,**kwargs): # 獲取所有數據 ret=models.Book.objects.all() # 創建分頁對象 page=PageNumberPagination() # 在數據庫中獲取分頁的數據 page_list=page.paginate_queryset(ret,request,view=self) # 對分頁進行序列化 ser=BookSerializer1(instance=page_list,many=True) return Response(ser.data) # 二 自定制 url=http://127.0.0.1:8000/pager/?page=2&size=3 # size=30,無效,最多5條 class Mypage(PageNumberPagination): page_size = 2 page_query_param = 'page' # 定制傳參 page_size_query_param = 'size' # 最大一頁的數據 max_page_size = 5 class Pager(APIView): def get(self,request,*args,**kwargs): # 獲取所有數據 ret=models.Book.objects.all() # 創建分頁對象 page=Mypage() # 在數據庫中獲取分頁的數據 page_list=page.paginate_queryset(ret,request,view=self) # 對分頁進行序列化 ser=BookSerializer1(instance=page_list,many=True) # return Response(ser.data) # 這個也是返回Response對象,但是比基本的多了上一頁,下一頁,和總數據條數(了解即可) return page.get_paginated_response(ser.data)
setting裏
REST_FRAMEWORK = {
# 每頁顯示兩條
'PAGE_SIZE':2
}
路由:
url(r'^pager/$', views.Pager.as_view()),
Serializers
class BookSerializer1(serializers.ModelSerializer): class Meta: model=models.Book # fields="__all__" exclude=('authors',)
使用方法:
- 1 導入PageNumberPagination類
- 2 實例化產生一個對象
page_pagination = PageNumberPagination() - 3 需要配置四個參數:page_size,page_query_param,page_size_query_param,max_page_size
page_size必須指定:在setting中指定或者直接賦值 - 4 調用下面的方法,返回ret數據
ret = page_pagination.paginate_queryset(book_list, request, self) - 5 再序列化,就是序列化返回的數據,也就是ret
類中需要掌握的幾個屬性
-page_size:控制每頁顯示條數
-page_query_param:控制查詢第幾頁的查詢參數,
-比如page_query_param='xx'
-http://127.0.0.1:8000/books/?xx=2 表示查詢第二頁的數據
-page_size_query_param:控制每頁最大顯示的條數
-比如page_pagination.page_size_query_param='max'
-http://127.0.0.1:8000/books/?xx=2&max=6 表示查詢第二頁的數據,每頁顯示6條
-max_page_size:控制每頁最大顯示的條數
-比如:page_pagination.max_page_size=7
-http://127.0.0.1:8000/books/?max=1000 最多顯示7條
2、偏移分頁(在第n個位置,向後查看n條數據)
使用方式:
? 同簡單分頁
重點的參數:
-default_limit:默認每頁顯示的條數,默認偏移的數量
-比如:default_limit=5
-http://127.0.0.1:8000/books/ 就會顯示5條數據
-limit_query_param:往後偏移多少條
-就用默認值:limit
-offset_query_param:標桿值
-用默認值:offset
limit_query_param+offset_query_param聯合起來用:
-訪問:http://127.0.0.1:8000/books/?limit=1&offset=5 表示:以數據的第5條作為標桿,往後偏移1條
-max_limit:最大偏移的條數(最大取出的條數)
# http://127.0.0.1:8000/pager/?offset=4&limit=3
from rest_framework.pagination import LimitOffsetPagination
# 也可以自定制,同簡單分頁
class Pager(APIView):
def get(self,request,*args,**kwargs):
# 獲取所有數據
ret=models.Book.objects.all()
# 創建分頁對象
page=LimitOffsetPagination()
# 在數據庫中獲取分頁的數據
page_list=page.paginate_queryset(ret,request,view=self)
# 對分頁進行序列化
ser=BookSerializer1(instance=page_list,many=True)
# return page.get_paginated_response(ser.data)
return Response(ser.data)
3、 CursorPagination(加密分頁,只能看上一頁和下一頁,速度快)
重點參數:
-page_size:每頁顯示的條數
-cursor_query_param:不需要動
-ordering:按什麽排序
通過get_paginated_response返回結果中帶上一頁和下一頁的鏈接地址
page_pagination.get_paginated_response(book_ser.data) 方法的用法
from rest_framework.pagination import CursorPagination
# 看源碼,是通過sql查詢,大於id和小於id
class Pager(APIView):
def get(self,request,*args,**kwargs):
# 獲取所有數據
ret=models.Book.objects.all()
# 創建分頁對象
page=CursorPagination()
page.ordering='nid'
# 在數據庫中獲取分頁的數據
page_list=page.paginate_queryset(ret,request,view=self)
# 對分頁進行序列化
ser=BookSerializer1(instance=page_list,many=True)
# 可以避免頁碼被猜到
return page.get_paginated_response(ser.data)
二、url控制器
1、自定義路由
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^books/$', views.BookView.as_view()),
url(r'^books/(?P<pk>\d+)$', views.BookDetailView.as_view()),
]
class BookView(APIView):
def get(self, request):
book_list = models.Book.objects.all()
bs = BookSerializers(book_list, many=True)
return Response(bs.data)
def post(self, request):
# 添加一條數據
print(request.data)
bs=BookSerializers(data=request.data)
if bs.is_valid():
bs.save() # 生成記錄
return Response(bs.data)
else:
return Response(bs.errors)
class BookDetailView(APIView):
def get(self,request,pk):
book_obj=models.Book.objects.filter(pk=pk).first()
bs=BookSerializers(book_obj,many=False)
return Response(bs.data)
def put(self,request,pk):
book_obj = models.Book.objects.filter(pk=pk).first()
bs=BookSerializers(data=request.data,instance=book_obj)
if bs.is_valid():
bs.save() # update
return Response(bs.data)
else:
return Response(bs.errors)
def delete(self,request,pk):
models.Book.objects.filter(pk=pk).delete()
return Response("")
2、半自動路由(試圖類繼承ModelViewSet)
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^publish/$', views.PublishView.as_view({'get':'list','post':'create'})),
url(r'^publish/(?P<pk>\d+)/$', views.PublishView.as_view({'get':'retrieve','put':'update','delete':'destroy'})),
]
from rest_framework.viewsets import ModelViewSet
class PublishView(ModelViewSet):
queryset=models.Publish.objects.all()
serializer_class=PublishSerializers
3、全自動路由(自動路由生成)
from django.conf.urls import url,include
from app01 import views
from rest_framework import routers
#生成一個router對象
router=routers.DefaultRouter()
# 兩個參數,一個是匹配的路由,一個是視圖中寫的CBV的類
router.register('publish',views.PublishView)
urlpatterns = [
# http://127.0.0.1:8000/publish/format=json(渲染器通過這個判斷,返回渲染的頁面)
# url(r'^publish/', views.PublishView.as_view({'get':'list','post':'create'})),
# http://127.0.0.1:8000/publish.json(渲染器通過這個判斷,返回渲染的頁面)
# url(r'^publish\.(?P<format>\w+)$', views.PublishView.as_view({'get':'list','post':'create'})),
# 可以用 以下方式訪問
# 1 http://127.0.0.1:8000/publish/
# 2 http://127.0.0.1:8000/publish.json
# 3 http://127.0.0.1:8000/publish/3
# 4 http://127.0.0.1:8000/publish/3.json
url(r'',include(router.urls))
]
from rest_framework.viewsets import ModelViewSet
class PublishView(ModelViewSet):
queryset=models.Publish.objects.all()
serializer_class=PublishSerializers
三、響應器
1、 作用
根據 用戶請求URL 或 用戶可接受的類型,篩選出合適的 渲染組件。
用戶請求URL:
http://127.0.0.1:8000/test/?format=json
http://127.0.0.1:8000/test.json
2、 內置渲染器
顯示json格式:JSONRenderer
訪問URL:
- http://127.0.0.1:8000/test/?format=json
- http://127.0.0.1:8000/test.json
- http://127.0.0.1:8000/test/
默認顯示格式:BrowsableAPIRenderer(可以修改它的html文件)
訪問URL:
- http://127.0.0.1:8000/test/?format=api
- http://127.0.0.1:8000/test.api
- http://127.0.0.1:8000/test/
表格方式:AdminRenderer
訪問URL:
- http://127.0.0.1:8000/test/?format=admin
- http://127.0.0.1:8000/test.admin
- http://127.0.0.1:8000/test/
form表單方式:HTMLFormRenderer
訪問URL:
- http://127.0.0.1:8000/test/?format=form
- http://127.0.0.1:8000/test.form
- http://127.0.0.1:8000/test/
3、局部使用
from rest_framework.renderers import HTMLFormRenderer,BrowsableAPIRenderer
class BookDetailView(APIView):
renderer_classes = [HTMLFormRenderer,BrowsableAPIRenderer ]
def get(self,request,pk):
book_obj=models.Book.objects.filter(pk=pk).first()
bs=BookSerializers(book_obj,many=False)
return Response(bs.data)
def put(self,request,pk):
book_obj = models.Book.objects.filter(pk=pk).first()
bs=BookSerializers(data=request.data,instance=book_obj)
if bs.is_valid():
bs.save() # update
return Response(bs.data)
else:
return Response(bs.errors)
def delete(self,request,pk):
models.Book.objects.filter(pk=pk).delete()
return Response("")
4、全局使用
settings裏配置:
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES':['rest_framework.renderers.JSONRenderer']
}
5、自定義顯示模版
from rest_framework.renderers import TemplateHTMLRenderer
class BookDetailView(APIView):
renderer_classes = [TemplateHTMLRenderer]
def get(self,request,pk):
book_obj=models.Book.objects.filter(pk=pk).first()
bs=BookSerializers(book_obj,many=False)
return Response(bs.data,template_name='aa.html')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ title }}
{{ publishDate }}
</body>
</html>
註意:如果同時多個存在時,自動根據URL後綴來選擇渲染器。
四、解析器
1、解析器的作用
根據請求頭 content-type 選擇對應的解析器對請求體內容進行處理。
有application/json,x-www-form-urlencoded,form-data等格式
2、全局使用解析器
setting裏
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES':[
'rest_framework.parsers.JSONParser'
'rest_framework.parsers.FormParser'
'rest_framework.parsers.MultiPartParser'
]
}
路由:
urlpatterns = [
url(r'test/', TestView.as_view()),
]
視圖函數:
from rest_framework.views import APIView
from rest_framework.response import Response
class TestView(APIView):
def post(self, request, *args, **kwargs):
print(request.content_type)
# 獲取請求的值,並使用對應的JSONParser進行處理
print(request.data)
# application/x-www-form-urlencoded 或 multipart/form-data時,request.POST中才有值
print(request.POST)
print(request.FILES)
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
3、局部使用解析器
a. 僅處理請求頭content-type為application/json的請求體
from django.conf.urls import url, include
from web.views.s5_parser import TestView
urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import JSONParser
class TestView(APIView):
parser_classes = [JSONParser, ]
def post(self, request, *args, **kwargs):
print(request.content_type)
# 獲取請求的值,並使用對應的JSONParser進行處理
print(request.data)
# application/x-www-form-urlencoded 或 multipart/form-data時,request.POST中才有值
print(request.POST)
print(request.FILES)
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
b. 僅處理請求頭content-type為application/x-www-form-urlencoded 的請求體
from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import FormParser
class TestView(APIView):
parser_classes = [FormParser, ]
def post(self, request, *args, **kwargs):
print(request.content_type)
# 獲取請求的值,並使用對應的JSONParser進行處理
print(request.data)
# application/x-www-form-urlencoded 或 multipart/form-data時,request.POST中才有值
print(request.POST)
print(request.FILES)
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
c. 僅處理請求頭content-type為multipart/form-data的請求體
from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import MultiPartParser
class TestView(APIView):
parser_classes = [MultiPartParser, ]
def post(self, request, *args, **kwargs):
print(request.content_type)
# 獲取請求的值,並使用對應的JSONParser進行處理
print(request.data)
# application/x-www-form-urlencoded 或 multipart/form-data時,request.POST中才有值
print(request.POST)
print(request.FILES)
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://127.0.0.1:8000/test/" method="post" enctype="multipart/form-data">
<input type="text" name="user" />
<input type="file" name="img">
<input type="submit" value="提交">
</form>
</body>
</html>
d. 僅上傳文件
from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'test/(?P<filename>[^/]+)', TestView.as_view(), name='test'),
]
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import FileUploadParser
class TestView(APIView):
parser_classes = [FileUploadParser, ]
def post(self, request, filename, *args, **kwargs):
print(filename)
print(request.content_type)
# 獲取請求的值,並使用對應的JSONParser進行處理
print(request.data)
# application/x-www-form-urlencoded 或 multipart/form-data時,request.POST中才有值
print(request.POST)
print(request.FILES)
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://127.0.0.1:8000/test/f1.numbers" method="post" enctype="multipart/form-data">
<input type="text" name="user" />
<input type="file" name="img">
<input type="submit" value="提交">
</form>
</body>
</html>
e. 同時多個Parser
當同時使用多個parser時,rest framework會根據請求頭content-type自動進行比對,並使用對應parser
from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import JSONParser, FormParser, MultiPartParser
class TestView(APIView):
parser_classes = [JSONParser, FormParser, MultiPartParser, ]
def post(self, request, *args, **kwargs):
print(request.content_type)
# 獲取請求的值,並使用對應的JSONParser進行處理
print(request.data)
# application/x-www-form-urlencoded 或 multipart/form-data時,request.POST中才有值
print(request.POST)
print(request.FILES)
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
4、源碼分析
1 在調用request.data時,才進行解析,由此入手
@property
def data(self):
if not _hasattr(self, '_full_data'):
self._load_data_and_files()
return self._full_data
2 查看self._load_data_and_files()方法---->self._data, self._files = self._parse()
def _parse(self):
#用戶請求頭裏content_type的值
media_type = self.content_type
#self.parsers 就是用戶配置的parser_classes = [FileUploadParser,FormParser ]
#self裏就有content_type,傳入此函數
parser = self.negotiator.select_parser(self, self.parsers)
3 查看self.negotiator.select_parser(self, self.parsers)
def select_parser(self, request, parsers):
#同過media_type和request.content_type比較,來返回解析器,然後調用解析器的解析方法
#每個解析器都有media_type = 'multipart/form-data'屬性
for parser in parsers:
if media_type_matches(parser.media_type, request.content_type):
return parser
return None
4 最終調用parser的解析方法來解析parsed = parser.parse(stream, media_type, self.parser_context)
1 Request實例化,parsers=self.get_parsers()
Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
2 get_parsers方法,循環實例化出self.parser_classes中類對象
def get_parsers(self):
return [parser() for parser in self.parser_classes]
3 self.parser_classes 先從類本身找,找不到去父類找即APIVIew 中的
parser_classes = api_settings.DEFAULT_PARSER_CLASSES
4 api_settings是一個對象,對象裏找DEFAULT_PARSER_CLASSES屬性,找不到,會到getattr方法
def __getattr__(self, attr):
if attr not in self.defaults:
raise AttributeError("Invalid API setting: '%s'" % attr)
try:
#調用self.user_settings方法,返回一個字典,字典再取attr屬性
val = self.user_settings[attr]
except KeyError:
# Fall back to defaults
val = self.defaults[attr]
# Coerce import strings into classes
if attr in self.import_strings:
val = perform_import(val, attr)
# Cache the result
self._cached_attrs.add(attr)
setattr(self, attr, val)
return val
5 user_settings方法 ,通過反射去setting配置文件裏找REST_FRAMEWORK屬性,找不到,返回空字典
@property
def user_settings(self):
if not hasattr(self, '_user_settings'):
self._user_settings = getattr(settings, 'REST_FRAMEWORK', {})
return self._user_settings
RESTFULL 07 rest-framework分頁器,相應器,解析器,url控制器,版本控制