Django-restframework之路由控制、解析器及响应器

时间:2023-03-08 17:18:31

django-restframework之路由控制、解析器及响应器

一 前言

本篇博客介绍 restframework 框架的剩下几个组件,路由控制有三种:传统路由、半自动路由及全自动路由;解析器是用来解析要响应的数据格式,比如是form-datajson、或是urlencoded等数据格式;响应器根据用户请求 url 或用户可以接受的数据格式来筛选出合适的渲染组件。

二 路由控制

一 传统路由

urls.py

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()),
]

views.py

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("")

二 半自动路由(视图类继承 ModelViewSet)

原理就是重写 as_view方法,以致可以找到请求方法和响应视图方法的对应关系。

urls.py

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'})), ]

views.py

from rest_framework.viewsets import ModelViewSet
class PublishView(ModelViewSet):
queryset=models.Publish.objects.all()
serializer_class=PublishSerializers

三 全自动路由(自动生成路由)

urls.py

from django.conf.urls import url,include
from app01 import views
from rest_framework import routers
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))
]

views.py

from rest_framework.viewsets import ModelViewSet
class PublishView(ModelViewSet):
queryset=models.Publish.objects.all()
serializer_class=PublishSerializers

三 解析器

一 解析器的作用

根据请求头的Content-Type参数来选择对应的解析器对请求体内容进行处理,有application/jsonx-www-form-urlencodedform-data等格式。

二 全局使用解析器

settings.py

REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES':[
'rest_framework.parsers.JSONParser'
'rest_framework.parsers.FormParser'
'rest_framework.parsers.MultiPartParser'
] }

urls.py

urlpatterns = [
url(r'test/', TestView.as_view()),
]

views.py

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请求,响应内容')

三 局部使用解析器

  1. 仅处理请求头 content-type 为 application/json 的请求体

urls.py

from django.conf.urls import url, include
from web.views.s5_parser import TestView urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]

views.py

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请求,响应内容')
  1. 仅处理请求头 content-type 为 application/x-www-form-urlencoded 的请求体

urls.py

from django.conf.urls import url, include
from web.views import TestView urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]

views.py

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请求,响应内容')
  1. 仅处理请求头 content-type 为 multipart/form-data 的请求体

urls.py

from django.conf.urls import url, include
from web.views import TestView urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]

views.py

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请求,响应内容')

html

<!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>
  1. 仅上传文件

urls.py

from django.conf.urls import url, include
from web.views import TestView urlpatterns = [
url(r'test/(?P<filename>[^/]+)', TestView.as_view(), name='test'),
]

views.py

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请求,响应内容')

html

<!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>
  1. 同时多个 parser

当同时使用多个 parser 时,restframework 会根据请求头 content-ty 自动进行对应,并使用相应的 parset

urls.py

from django.conf.urls import url, include
from web.views import TestView urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]

views.py

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请求,响应内容')

四 解析器源码分析

当调用request.data时才进行解析数据,这里的 request 是Request类对象。

1. request.data

Django-restframework之路由控制、解析器及响应器

2. request._load_data_and_files

Django-restframework之路由控制、解析器及响应器

3. request._parse

Django-restframework之路由控制、解析器及响应器

4. request._stream

Django-restframework之路由控制、解析器及响应器

5. self.parsers

Django-restframework之路由控制、解析器及响应器

6. self.parser_classes

Django-restframework之路由控制、解析器及响应器

self.parser_classes就是设置在视图类中的一个列表

7. self.negotiator.select_parser

Django-restframework之路由控制、解析器及响应器

根据数据格式选择对应的数据解析器

8. self.get_parser_context

Django-restframework之路由控制、解析器及响应器

9. stream、media_type和 self.parser_context准备好

Django-restframework之路由控制、解析器及响应器

10. 假设该解析器为 JSONParser

Django-restframework之路由控制、解析器及响应器

四 响应器

一 作用

根据用户请求的 URL 或用户可接受的数据类型,筛选出合适的渲染组件。

用户请求 URL:

二内置渲染器

显示 json 格式:JSONRenderer

访问 url:

默认显示格式:BrowsableAPIRenderer(可以修改 html 文件)

访问 url:

表格方式:AdminRenderer

访问 url:

form 表单方式:HTMLFormRenderer

访问 url:

三 局部使用

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("")

四 全局使用

REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES':['rest_framework.renderers.JSONRenderer']
}

五 自定义显示模板

views.py

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')

html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ title }}
{{ publishDate }}
</body>
</html>