一、解析器(parser)

  解析器在reqest.data取值的时候才执行。

  对请求的数据进行解析:是针对请求体进行解析的。表示服务器可以解析的数据格式的种类。

from rest_framework.parsers import JSONParser, FormParser, MultiPartParser, FileUploadParser
"""
默认得是 JSONParser FormParser MultiPartParser
"""
class BookView(APIView):
# authentication_classes = [TokenAuth, ]
parser_classes = [FormParser, JSONParser] def get(self, request):....

1、django的request类源码解析

(1)django中发送请求对比

#如果是urlencoding格式发送的数据,在POST里面有值
Content-Type: application/url-encoding.....
request.body
request.POST #如果是发送的json格式数据,在POST里面是没有值的,在body里面有值,可通过decode,然后loads取值
Content-Type: application/json.....
request.body
request.POST

(2)关于decode和encode

  浏览器发送过来是字节需要先解码 ---> decode 如:s=‘中文‘

  如果是在utf8的文件中,该字符串就是utf8编码,如果是在gb2312的文件中,则其编码为gb2312。这种情况下,要进行编码转换,都需要先用 decode方法将其转换成unicode编码,再使用encode方法将其转换成其他编码。通常,在没有指定特定的编码方式时,都是使用的系统默认编码创建的代码文件。 如下:

  s.decode(‘utf-8‘).encode(‘utf-8‘)

  decode():是解码 --->把字节变成字符串      encode()是编码---->把字符串变成字节

(3)查看django中WSGIRequest解析方法

# 1:导入django的类
from django.core.handlers.wsgi import WSGIRequest # 2:
class WSGIRequest(http.HttpRequest):
def _get_post(self):
if not hasattr(self, ‘_post‘):
self._load_post_and_files()
return self._post
# 3:self._load_post_and_files()从这里找到django解析的方法
def _load_post_and_files(self):
"""Populate self._post and self._files if the content-type is a form type"""
if self.method != ‘POST‘:
self._post, self._files = QueryDict(encoding=self._encoding), MultiValueDict()
return
if self._read_started and not hasattr(self, ‘_body‘):
self._mark_post_parse_error()
return if self.content_type == ‘multipart/form-data‘:
if hasattr(self, ‘_body‘):
# Use already read data
data = BytesIO(self._body)
else:
data = self
try:
self._post, self._files = self.parse_file_upload(self.META, data)
except MultiPartParserError:
# An error occurred while parsing POST data. Since when
# formatting the error the request handler might access
# self.POST, set self._post and self._file to prevent
# attempts to parse POST data again.
# Mark that an error occurred. This allows self.__repr__ to
# be explicit about it instead of simply representing an
# empty POST
self._mark_post_parse_error()
raise
elif self.content_type == ‘application/x-www-form-urlencoded‘:
self._post, self._files = QueryDict(self.body, encoding=self._encoding), MultiValueDict()
else:
self._post, self._files = QueryDict(encoding=self._encoding), MultiValueDict()

  从if self.content_type == ‘multipart/form-data‘:和 self.content_type == ‘application/x-www-form-urlencoded‘: 可以知道django只解析urlencoded‘和form-data这两种类型。

  因此在django中传json数据默认是urlencoded解析到request中:body取到json数据时,取到的数据时字节,需要先decode解码,将字节变成字符串。

request.body.decode("utf8")
json.loads(request.body.decode("utf8"))

  为了传输json数据每次都要decode\loads,比较麻烦因此才有了解析器解决这个问题。

2、rest-framework的request类源码解析

  在rest-framework中 是以利用Request类进行数据解析。

1:找到apiview
class APIView(View):
# The following policies may be set at either globally, or per-view.
renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
parser_classes = api_settings.DEFAULT_PARSER_CLASSES # 解析器 2:找api_settings没有定义找默认
renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES 3:.
api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS) 4:DEFAULTS DEFAULTS = {
# Base API policies # 自带的解析器
‘DEFAULT_PARSER_CLASSES‘: (
‘rest_framework.parsers.JSONParser‘,    # 仅处理请求头content-type为application/json的请求体
‘rest_framework.parsers.FormParser‘,    # 仅处理请求头content-type为application/x-www-form-urlencoded 的请求体
‘rest_framework.parsers.MultiPartParser‘  # 仅处理请求头content-type为multipart/form-data的请求体
),

  注意除了上面三种之外还有一个专门处理文件上传:

from rest_framework.parsers import FileUploadParser

3、局部视图parser

from rest_framework.parsers import JSONParser,FormParser
class PublishViewSet(generics.ListCreateAPIView):
parser_classes = [FormParser,JSONParser]
queryset = Publish.objects.all()
serializer_class = PublshSerializers
def post(self, request, *args, **kwargs):
print("request.data",request.data)
return self.create(request, *args, **kwargs)

4、全局视图parser

REST_FRAMEWORK={
"DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
"DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
"DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",],
"DEFAULT_THROTTLE_RATES":{
"visit_rate":"5/m",
},
"DEFAULT_PARSER_CLASSES":['rest_framework.parsers.FormParser',]
}

二、url路由控制

  因为我们使用的是视图集而不是视图,我们可以通过简单地将视图集注册到router类来为我们的API自动生成URL conf。

  同样,如果我们需要对API URL有更多的控制,我们可以直接使用常规的基于类的视图,并显式地编写URL conf。

  最后,我们将默认登录和注销视图包含在可浏览API中。这是可选的,但如果您的API需要身份验证,并且希望使用可浏览的API,那么这是有用的。

1、全自动路由示例

from django.contrib import admin

from django.urls import path, re_path, include
from rest_framework import routers
from app01 import views routers = routers.DefaultRouter() # 实例化
routers.register("authors", views.AuthorViewSet) # 注册某一个视图 urlpatterns = [
path('admin/', admin.site.urls),
...
# as_view参数指定什么请求走什么方法
# re_path(r'^authors/$', views.AuthorViewSet.as_view({"get": "list", "post": "create"}), name="author_list"),
# re_path(r'^authors/(?P<pk>\d+)/$', views.AuthorViewSet.as_view({
# 'get': 'retrieve',
# 'put': 'update',
# 'patch': 'partial_update',
# 'delete': 'destroy'
# }), name="author_detail"), # 改写如下:
re_path(r"", include(routers.urls)), re_path(r'^login/$', views.LoginView.as_view(), name="login"),
]

  视图的内容不需要任何变动即生效:

  

  

  

2、DRF路由组件使用

  路由传参写的特别多,但是框架将这些也已经封装好了。

  修改DRFDemo/urls.py文件如下所示:

from django.urls import path, include
from .views import BookView, BookEditView, BookModelViewSet
from rest_framework.routers import DefaultRouter router = DefaultRouter() # 路由实例化
# 第一个参数是路由匹配规则,这里的路由是分发下来的,因此可以不做设置;第二个参数是视图
router.register(r"", BookModelViewSet) urlpatterns = [
# path('list', BookView.as_view()), # 查看所有的图书
# 注意url中参数命名方式,2.0之前的写法:'retrieve/(?P<id>\d+)'
# 2.0之后的写法:<>内声明类型,冒号后面跟着关键字参数
# path('retrieve/<int:id>', BookEditView.as_view()) # 单条数据查看 # path('list', BookModelViewSet.as_view({"get": "list", "post": "create"})),
# path('retrieve/<int:id>', BookModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"}))
] urlpatterns += router.urls # router.urls是自动生成带参数的路由

  但是需要自定制的时候还是需要我们自己用APIView写,当不需要那么多路由的时候,不要用这种路由注册,否则会对外暴露过多的接口,会存在风险。总之,一切按照业务需要去用。

三、分页组件(Pagination)

REST框架支持自定义分页风格,你可以修改每页显示数据集合的最大长度。

分页链接支持以下两种方式提供给用户:

  • 分页链接是作为响应内容提供给用户
  • 分页链接被包含在响应头中(Content-Range或者Link)

内建风格使用作为响应内容提供给用户。这种风格更容易被使用可浏览API的用户所接受。

  如果使用通用视图或者视图集合。系统会自动帮你进行分页。

  如果使用的是APIView,你就需要自己调用分页API,确保返回一个分页后的响应。可以将pagination_class设置为None关闭分页功能。

1、设置分页风格

  可以通过设置DEFAULT_PAGINATION_CLASS和PAGE_SIZE,设置全局变量。

REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 100
}

  需要同时设置pagination class和page size。 也可以在单个视图中设置pagination_class属性,但一般你需要使用统一的分页风格。

2、修改分页风格

  如果你需要修改分页风格 ,需要重写分页类,并设置你需要修改的属性。

from rest_framework.views import APIView
from rest_framework.response import Response
from app01.serializer import *
from .utils import *
#分页
from rest_framework.pagination import PageNumberPagination class MyPageNumberPagination(PageNumberPagination):
# 默认每页显示的数据条数
page_size = 2
# 获取URL参数中设置的每页显示数据条数
page_size_query_param = 'size'
# 获取URL参数中传入的页码key
page_query_param = 'page'
# 最大支持的每页显示的数据条数(对这个进行限制127.0.0.1:8000/books/?page=1&size=100)
max_page_size = 3 class BookView(APIView):
# authentication_classes = [TokenAuth, ]
# parser_classes = [FormParser, JSONParser]
pagination_class = MyPageNumberPagination # 在视图中使用pagination_class属性调用该自定义类
def get(self, request):
book_list = Book.objects.all() # queryset # 实例化分页对象,获取数据库中的分页数据
pnp = MyPageNumberPagination()
books_page = pnp.paginate_queryset(book_list, request, self)
# 序列化对象
bs = BookModelSerializers(books_page, many=True, context={"request": request}) # 序列化结果
# return Response(bs.data)
return bs.get_paginated_response(bs.data) # 生成分页和数据 def post(self, request):.....

(1)设置max_page_size是限制直接在页面访问时最大的数据条数显示

  

  虽然总共有4条数据,页面访问get请求时?page=1&size=100但是依然只能拿到max_page_size限制拿到的3条。

3、根据页码分页——PageNumberPagination

  这个分页样式接受请求查询参数中的一个数字页面号。

GET https://api.example.org/accounts/?page=4

  响应对象:

HTTP 200 OK
{
"count": 1023
"next": "https://api.example.org/accounts/?page=5",
"previous": "https://api.example.org/accounts/?page=3",
"results": [

]
}

  继承了APIView的视图,也可以设置pagination_class属性选择PageNumberPagination

class MyPageNumberPagination(PageNumberPagination):
# 默认每页显示的数据条数
page_size = 1 # 获取URL参数中设置的每页显示数据条数
page_size_query_param = 'size' # 获取URL参数中传入的页码key
page_query_param = 'page' # 最大支持的每页显示的数据条数(对这个进行限制127.0.0.1:8000/books/?page=1&size=100)
max_page_size = 3

  更多配置属性:

  • django_paginator_class  使用Django分页类。默认为django.core.paginator.Paginator,适用于大多数情况
  • page_size  用来显示每页显示对象的数量,如果设置了就重写PAGE_SIZE设置。
  • page_query_param  页面查询参数,一个字符串值,指示用于分页控件的查询参数的名称。
  • page_size_query_param  该参数允许客户端根据每个请求设置页面大小。一般默认设置为None.
  • max_page_size  只有设置了page_size_query_param参数,该参数才有意义,为客户端请求页面中能够显示的最大数量
  • last_page_strings  用于存储使用page_query_param参数请求过的值列表或元组,默认为(‘last’,)
  • template  用来在可浏览API中,渲染分页的模板(html)名字,可以重写分页样式,或者设置为None,禁用分页。默认为”rest_framework/pagination/numbers.html”。

4、根据位置和个数分页——LimitOffsetPagination

  这种分页样式与查找多个数据库记录时使用的语法类似。客户端包括一个”limit”和一个 “offset”查询参数。该限制表示返回的条目的最大数量,并且与page_size大小相同。偏移量表示查询的起始位置,与完整的未分页项的集合有关。

GET https://api.example.org/accounts/?limit=100&offset=400

HTTP 200 OK
{
"count": 1023
"next": "https://api.example.org/accounts/?limit=100&offset=500",
"previous": "https://api.example.org/accounts/?limit=100&offset=300",
"results": [

]
}

  这种也可以设置PAGE_SIZE,然后客户端就可以设置limit参数了。
  继承了GenericAPIView的子类,可以通过设置pagination_class属性为LimitOffsetPagination使用

class MyLimitOffsetPagination(LimitOffsetPagination):
# 默认每页显示的数据条数
default_limit = 1
# URL中传入的显示数据条数的参数
limit_query_param = 'limit'
# URL中传入的数据位置的参数
offset_query_param = 'offset'
# 最大每页显得条数
max_limit = None

(重写LimitOffsetPagination类)配置:

  • default_limit: 如果客户端没有提供,则默认使用与PAGE_SIZE值一样。
  • limit_query_param:表示限制查询参数的名字,默认为’limit’
  • offset_query_param:表示偏移参数的名字, 默认为’offset’
  • max_limit:允许页面中显示的最大数量,默认为None
  • template: 渲染分页结果的模板名,默认为”rest_framework/pagination/numbers.html”.

5、游标分页——CursorPagination

  基于游标的分页显示了一个不透明的“cursor”指示器,客户端可以使用它来浏览结果集。这种分页方式只允许用户向前或向后进行查询。并且不允许客户端导航到任意位置。

  基于游标的分页要求在结果集中有一个惟一的、不变的条目顺序。这个排序通常是记录上的一个创建时间戳,用来表示分页的顺序。

  基于游标的分页比其他方案更复杂。它还要求结果集给出一个固定的顺序,并且不允许客户端任意地对结果集进行索引,但是它确实提供了以下好处:

  • 提供一致的分页视图。当使用正确的指针分页时,即使在分页过程中其他客户端插入新项时,客户端也不会在分页时看到同一个项两次。
  • 支持使用非常大的数据集。大量数据集使用基于off-set的分页方式可能会变得低效或不可用。基于指针的分页模式有固定的时间属性,并且随着数据集的大小的增加而不会减慢。
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination

class MyCursorPagination(CursorPagination):
# URL传入的游标参数
cursor_query_param = 'cursor'
# 默认每页显示的数据条数
page_size = 2
# URL传入的每页显示条数的参数
page_size_query_param = 'page_size'
# 每页显示数据最大条数
max_page_size = 1000
# 根据ID从大到小排列
ordering = "id"

6、设置全局配置

REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
# 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
# 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.CursorPagination',
'PAGE_SIZE': 100
}

  显示效果:

  

四、响应器(response)

五、渲染器

  规定页面显示的效果(无用)。

1、局部添加渲染器

  urls.py:

from django.conf.urls import url, include
from api.views import course urlpatterns = [
# path('admin/', admin.site.urls),
url(r'^api/course/$', course.CourseView.as_view()),
]

  api/views/course.py:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer class CourseView(APIView): # 渲染器
# renderer_classes = [JSONRenderer] # 表示只返回json格式
renderer_classes = [JSONRenderer, BrowsableAPIRenderer] # 数据嵌套在html中展示 def get(self, request, *args, **kwargs):
return Response('...')

  显示效果:

  

2、全局添加渲染器

  settings.py:

# 渲染器配置到全局
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': ['rest_framework.renderers.JSONRenderer','rest_framework.renderers.BrowsableAPIRenderer']
}

  显示效果同上。

rest-framework框架——解析器、ur控制、分页、响应器、渲染器、版本的更多相关文章

  1. rest-framework解析器,url控制,分页,响应器,渲染器,版本控制

    解析器 1.json解析器 发一个json格式的post请求.后台打印: request_data---> {'title': '北京折叠'} request.POST---> <Q ...

  2. Django_rest_framework_渲染器/解析器/路由控制/分页

    目录 渲染器 解析器 路由控制 分页 渲染器 简介 什么是渲染器 根据 用户请求URL 或 用户可接受的类型,筛选出合适的 渲染组件. 渲染器的作用 序列化.友好的展示数据 渲染器配置 首先要在set ...

  3. rest-framework之响应器(渲染器)

    rest-framework之响应器(渲染器) 本文目录 一 作用 二 内置渲染器 三 局部使用 四 全局使用 五 自定义显示模版 回到目录 一 作用 根据 用户请求URL 或 用户可接受的类型,筛选 ...

  4. restful(3):认证、权限、频率 & 解析器、路由控制、分页、渲染器、版本

    models.py中: class UserInfo(models.Model): name = models.CharField(max_length=32) psw = models.CharFi ...

  5. 5 解析器、url路由控制、分页、渲染器和版本

    1 数据解析器 1 什么是解析器 相当于request 中content-type 对方传什么类型的数据,我接受什么样的数据:怎样解析 无论前面传的是什么数据,都可以解开 例如:django不能解析j ...

  6. Spring Framework框架解析(1)- 从图书馆示例来看xml文件的加载过程

    引言 这个系列是我阅读Spring源码后的一个总结,会从Spring Framework框架的整体结构进行分析,不会先入为主的讲解IOC或者AOP的原理,如果读者有使用Spring的经验再好不过.鉴于 ...

  7. rest-framework 响应器(渲染器)

    一 作用: 根据 用户请求URL 或 用户可接受的类型,筛选出合适的 渲染组件. 用户请求URL:    http://127.0.0.1:8000/test/?format=json    http ...

  8. 29.渲染器Renderer

    什么是渲染器     渲染器就是将服务器生成的数据格式转为http请求的格式   渲染器触发及参数配置 在DRF配置参数中,可用的渲染器作为一个类的列表进行定义 但与解析器不同的是,渲染器的列表是有顺 ...

  9. ArcGIS Engine专题地图渲染器的实现(入门版)

    专题地图(Thematic Map)是着重表示一种或数种自然要素特征或社会经济现象的地图 专题地图的内容由两部分构成: 1.专题内容——图上突出表示的自然或社会经济现象及其有关特征 2.地理基础——用 ...

随机推荐

  1. ORA-03113 : end-of-file on communication channel

    现象一: 数据库startup时,出现数据库无法正常mount,并报ORA-03113错误. SQL> startup ORACLE instance started. Total System ...

  2. Flink生态与未来

    本文为<Flink大数据项目实战>学习笔记,想通过视频系统学习Flink这个最火爆的大数据计算框架的同学,推荐学习课程: Flink大数据项目实战:http://t.cn/EJtKhaz ...

  3. flex弹性布局,好用

    一直不太喜欢自己布局前端页面,都是扒别人的页面 ,最近在练习小程序,页面无处可扒,只有自己布局 发现flex弹性布局真好用,布局起来很简单,实现的效果也很好,赞 以后可以自己写一点前端了,哈哈

  4. python语法学习面向对象之继承

    python语法学习面向对象之继承 转载自:http://www.cnblogs.com/Joans/archive/2012/11/09/2757368.html 只要涉及到面向对象,”类“是必须出 ...

  5. Luogu P1131 [ZJOI2007]时态同步 树形DP

    要自下向上调整,尽可能用一个道具修改多个: 搜的时候记录叶节点的最大深度,减一下就好了. #include<cstdio> #include<iostream> #includ ...

  6. POJ - 3263 差分+前缀和

    只需不断维护相对值的前缀就能得到解 这种思想第一次是在树状数组区间更新那里看到的,由于题目要求是1~n所以直接可以用前缀和维护 注意不能直接-1 +1 还有POJ的数据..要不是书里有提谁知道会这么毒 ...

  7. B - Toy Storage(POJ - 2398) 计算几何基础题,比TOYS多了个线段排序

    Mom and dad have a problem: their child, Reza, never puts his toys away when he is finished playing ...

  8. DenyHosts 阻止SSH暴力攻击

    当你的 Linux 服务器暴露在互联网之中,该服务器将会遭到互联网上的扫描软件进行扫描,并试图猜测SSH登录口令. 你会发现,每天会有多条SSH登录失败纪录.那些扫描工具将对你的服务器构成威胁,你必须 ...

  9. 网络那点事之socket队列

    1.socket 在内核中是怎么表示的,怎么与文件系统建立关系 2.socket在什么时候创建了接收队列,接收队列的长度是怎么确定的 3.接收到一个数据包根据怎么找到到接收队列的 使用hash算法,分 ...

  10. PHP房贷计算器代码,等额本息,等额本金

    debx(); function debx() { $dkm = 240; //贷款月数,20年就是240个月 $dkTotal = 10000; //贷款总额 $dknl = 0.0515; //贷 ...