Django Rest Framework
一. 什么是RESTful
- REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”
- REST从资源的角度类审视整个网络,它将分布在网络中某个节点的资源通过URL进行标识,客户端应用通过URL来获取资源的表征,获得这些表征致使这些应用转变状态
- REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”
- 所有的数据,不过是通过网络获取的还是操作(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其他架构风格的最本质属性
- 对于REST这种面向资源的架构风格,有人提出一种全新的结构理念,即:面向资源架构(ROA:Resource Oriented Architecture)
二. RESTful API设计
- API与用户的通信协议,总是使用HTTPs协议。
- 域名
- https://api.example.com 尽量将API部署在专用域名(会存在跨域问题)
- https://example.org/api/ API很简单
- 版本
- URL,如:https://api.example.com/v1/
- 请求头 跨域时,引发发送多次请求
- 路径,视网络上任何东西都是资源,均使用名词表示(可复数)
- https://api.example.com/v1/zoos
- https://api.example.com/v1/animals
- https://api.example.com/v1/employees
- method
- GET :从服务器取出资源(一项或多项)
- POST :在服务器新建一个资源
- PUT :在服务器更新资源(客户端提供改变后的完整资源)
- PATCH :在服务器更新资源(客户端提供改变的属性)
- DELETE :从服务器删除资源
- 过滤,通过在url上传参的形式传递搜索条件
- https://api.example.com/v1/zoos?limit=10:指定返回记录的数量
- https://api.example.com/v1/zoos?offset=10:指定返回记录的开始位置
- https://api.example.com/v1/zoos?page=2&per_page=100:指定第几页,以及每页的记录数
- https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序
- https://api.example.com/v1/zoos?animal_type_id=1:指定筛选条件
- 状态码
200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务) 204 NO CONTENT - [DELETE]:用户删除数据成功。 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。 403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。 406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
更多看这里:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
- 错误处理,状态码是4xx时,应返回错误信息,error当做key。
{ error: "Invalid API key" }
- 返回结果,针对不同操作,服务器向用户返回的结果应该符合以下规范。
GET /collection:返回资源对象的列表(数组) GET /collection/resource:返回单个资源对象 POST /collection:返回新生成的资源对象 PUT /collection/resource:返回完整的资源对象 PATCH /collection/resource:返回完整的资源对象 DELETE /collection/resource:返回一个空文档
- Hypermedia API,RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。
{"link": { "rel": "collection https://www.example.com/zoos", "href": "https://api.example.com/zoos", "title": "List of zoos", "type": "application/vnd.yourformat+json" }}
摘自:http://www.ruanyifeng.com/blog/2014/05/restful_api.html
三. 基于Django实现
路由系统:
urlpatterns = [ url(r'^users', Users.as_view()), ]
CBV视图:
from django.views import View from django.http import JsonResponseclass Users(View):
def get(self, request, *args, **kwargs):
result = {
'status': True,
'data': 'response data'
}
return JsonResponse(result, status=200)def post(self, request, *args, **kwargs): result = { 'status': True, 'data': 'response data' } return JsonResponse(result, status=200) </pre>
四. 基于Django Rest Framework框架实现
1. 基本流程
url.py
from django.conf.urls import url, include from web.views.s1_api import TestViewurlpatterns = [
url(r'^test/', TestView.as_view()),
]
views.py
from rest_framework.views import APIView from rest_framework.response import Responseclass TestView(APIView):
def dispatch(self, request, *args, **kwargs):
"""
请求到来之后,都要执行dispatch方法,dispatch方法根据请求方式不同触发 get/post/put等方法注意:APIView中的dispatch方法有好多好多的功能 """ return super().dispatch(request, *args, **kwargs) def get(self, request, *args, **kwargs): return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')</pre>
上述是rest framework框架基本流程,重要的功能是在APIView的dispatch中触发。
2. 认证和授权
a. 用户url传入的token认证
from django.conf.urls import url, include from web.viewsimport TestViewurlpatterns = [
url(r'^test/', TestView.as_view()),
]
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.authentication import BaseAuthentication from rest_framework.request import Request from rest_framework import exceptionstoken_list = [
'sfsfss123kuf3j123',
'asijnfowerkkf9812',
]class TestAuthentication(BaseAuthentication):
def authenticate(self, request):
"""
用户认证,如果验证成功后返回元组: (用户,用户Token)
:param request:
:return:
None,表示跳过该验证;
如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
self._authenticator = None
if api_settings.UNAUTHENTICATED_USER:
self.user = api_settings.UNAUTHENTICATED_USER()
else:
self.user = Noneif api_settings.UNAUTHENTICATED_TOKEN: self.auth = api_settings.UNAUTHENTICATED_TOKEN() else: self.auth = None (user,token)表示验证通过并设置用户名和Token; AuthenticationFailed异常 </span><span style="color: #800000;">"""</span><span style="color: #000000;"> val </span>= request.query_params.get(<span style="color: #800000;">'</span><span style="color: #800000;">token</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">if</span> val <span style="color: #0000ff;">not</span> <span style="color: #0000ff;">in</span><span style="color: #000000;"> token_list: </span><span style="color: #0000ff;">raise</span> exceptions.AuthenticationFailed(<span style="color: #800000;">"</span><span style="color: #800000;">用户认证失败</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">return</span> (<span style="color: #800000;">'</span><span style="color: #800000;">登录用户</span><span style="color: #800000;">'</span>, <span style="color: #800000;">'</span><span style="color: #800000;">用户token</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> authenticate_header(self, request): </span><span style="color: #800000;">"""</span><span style="color: #800000;"> Return a string to be used as the value of the `WWW-Authenticate` header in a `401 Unauthenticated` response, or `None` if the authentication scheme should return `403 Permission Denied` responses. </span><span style="color: #800000;">"""</span> <span style="color: #008000;">#</span><span style="color: #008000;"> 验证失败时,返回的响应头WWW-Authenticate对应的值</span> <span style="color: #0000ff;">pass</span>
class TestView(APIView):
authentication_classes = [TestAuthentication, ]
permission_classes = []</span><span style="color: #0000ff;">def</span> get(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.user) </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.auth) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">GET请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> post(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> put(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">PUT请求,响应内容</span><span style="color: #800000;">'</span>)</pre>
b. 请求头认证
from django.conf.urls import url, include from web.viewsimport TestViewurlpatterns = [
url(r'^test/', TestView.as_view()),
]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.authentication import BaseAuthentication from rest_framework.request import Request from rest_framework import exceptionstoken_list = [
'sfsfss123kuf3j123',
'asijnfowerkkf9812',
]class TestAuthentication(BaseAuthentication):
def authenticate(self, request):
"""
用户认证,如果验证成功后返回元组: (用户,用户Token)
:param request:
:return:
None,表示跳过该验证;
如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
self._authenticator = None
if api_settings.UNAUTHENTICATED_USER:
self.user = api_settings.UNAUTHENTICATED_USER()
else:
self.user = Noneif api_settings.UNAUTHENTICATED_TOKEN: self.auth = api_settings.UNAUTHENTICATED_TOKEN() else: self.auth = None (user,token)表示验证通过并设置用户名和Token; AuthenticationFailed异常 </span><span style="color: #800000;">"""</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> base64 auth </span>= request.META.get(<span style="color: #800000;">'</span><span style="color: #800000;">HTTP_AUTHORIZATION</span><span style="color: #800000;">'</span>, b<span style="color: #800000;">''</span><span style="color: #000000;">) </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> auth: auth </span>= auth.encode(<span style="color: #800000;">'</span><span style="color: #800000;">utf-8</span><span style="color: #800000;">'</span><span style="color: #000000;">) auth </span>=<span style="color: #000000;"> auth.split() </span><span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span> auth <span style="color: #0000ff;">or</span> auth[0].lower() != b<span style="color: #800000;">'</span><span style="color: #800000;">basic</span><span style="color: #800000;">'</span><span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> exceptions.AuthenticationFailed(<span style="color: #800000;">'</span><span style="color: #800000;">验证失败</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">if</span> len(auth) != 2<span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> exceptions.AuthenticationFailed(<span style="color: #800000;">'</span><span style="color: #800000;">验证失败</span><span style="color: #800000;">'</span><span style="color: #000000;">) username, part, password </span>= base64.b64decode(auth[1]).decode(<span style="color: #800000;">'</span><span style="color: #800000;">utf-8</span><span style="color: #800000;">'</span>).partition(<span style="color: #800000;">'</span><span style="color: #800000;">:</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">if</span> username == <span style="color: #800000;">'</span><span style="color: #800000;">alex</span><span style="color: #800000;">'</span> <span style="color: #0000ff;">and</span> password == <span style="color: #800000;">'</span><span style="color: #800000;">123</span><span style="color: #800000;">'</span><span style="color: #000000;">: </span><span style="color: #0000ff;">return</span> (<span style="color: #800000;">'</span><span style="color: #800000;">登录用户</span><span style="color: #800000;">'</span>, <span style="color: #800000;">'</span><span style="color: #800000;">用户token</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> exceptions.AuthenticationFailed(<span style="color: #800000;">'</span><span style="color: #800000;">用户名或密码错误</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> authenticate_header(self, request): </span><span style="color: #800000;">"""</span><span style="color: #800000;"> Return a string to be used as the value of the `WWW-Authenticate` header in a `401 Unauthenticated` response, or `None` if the authentication scheme should return `403 Permission Denied` responses. </span><span style="color: #800000;">"""</span> <span style="color: #0000ff;">return</span> <span style="color: #800000;">'</span><span style="color: #800000;">Basic realm=api</span><span style="color: #800000;">'</span>
class TestView(APIView):
authentication_classes = [TestAuthentication, ]
permission_classes = []</span><span style="color: #0000ff;">def</span> get(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.user) </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.auth) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">GET请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> post(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> put(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">PUT请求,响应内容</span><span style="color: #800000;">'</span>)</pre>
c. 多个认证规则
from django.conf.urls import url, include from web.views.s2_auth import TestViewurlpatterns = [
url(r'^test/', TestView.as_view()),
]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.authentication import BaseAuthentication from rest_framework.request import Request from rest_framework import exceptionstoken_list = [
'sfsfss123kuf3j123',
'asijnfowerkkf9812',
]class Test1Authentication(BaseAuthentication):
def authenticate(self, request):
"""
用户认证,如果验证成功后返回元组: (用户,用户Token)
:param request:
:return:
None,表示跳过该验证;
如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
self._authenticator = None
if api_settings.UNAUTHENTICATED_USER:
self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户
else:
self.user = Noneif api_settings.UNAUTHENTICATED_TOKEN: self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默认值为:None else: self.auth = None (user,token)表示验证通过并设置用户名和Token; AuthenticationFailed异常 </span><span style="color: #800000;">"""</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> base64 auth </span>= request.META.get(<span style="color: #800000;">'</span><span style="color: #800000;">HTTP_AUTHORIZATION</span><span style="color: #800000;">'</span>, b<span style="color: #800000;">''</span><span style="color: #000000;">) </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> auth: auth </span>= auth.encode(<span style="color: #800000;">'</span><span style="color: #800000;">utf-8</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> None </span><span style="color: #0000ff;">print</span>(auth,<span style="color: #800000;">'</span><span style="color: #800000;">xxxx</span><span style="color: #800000;">'</span><span style="color: #000000;">) auth </span>=<span style="color: #000000;"> auth.split() </span><span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span> auth <span style="color: #0000ff;">or</span> auth[0].lower() != b<span style="color: #800000;">'</span><span style="color: #800000;">basic</span><span style="color: #800000;">'</span><span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> exceptions.AuthenticationFailed(<span style="color: #800000;">'</span><span style="color: #800000;">验证失败</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">if</span> len(auth) != 2<span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> exceptions.AuthenticationFailed(<span style="color: #800000;">'</span><span style="color: #800000;">验证失败</span><span style="color: #800000;">'</span><span style="color: #000000;">) username, part, password </span>= base64.b64decode(auth[1]).decode(<span style="color: #800000;">'</span><span style="color: #800000;">utf-8</span><span style="color: #800000;">'</span>).partition(<span style="color: #800000;">'</span><span style="color: #800000;">:</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">if</span> username == <span style="color: #800000;">'</span><span style="color: #800000;">alex</span><span style="color: #800000;">'</span> <span style="color: #0000ff;">and</span> password == <span style="color: #800000;">'</span><span style="color: #800000;">123</span><span style="color: #800000;">'</span><span style="color: #000000;">: </span><span style="color: #0000ff;">return</span> (<span style="color: #800000;">'</span><span style="color: #800000;">登录用户</span><span style="color: #800000;">'</span>, <span style="color: #800000;">'</span><span style="color: #800000;">用户token</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">raise</span> exceptions.AuthenticationFailed(<span style="color: #800000;">'</span><span style="color: #800000;">用户名或密码错误</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> authenticate_header(self, request): </span><span style="color: #800000;">"""</span><span style="color: #800000;"> Return a string to be used as the value of the `WWW-Authenticate` header in a `401 Unauthenticated` response, or `None` if the authentication scheme should return `403 Permission Denied` responses. </span><span style="color: #800000;">"""</span> <span style="color: #008000;">#</span><span style="color: #008000;"> return 'Basic realm=api'</span> <span style="color: #0000ff;">pass</span>
class Test2Authentication(BaseAuthentication):
def authenticate(self, request):
"""
用户认证,如果验证成功后返回元组: (用户,用户Token)
:param request:
:return:
None,表示跳过该验证;
如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
self._authenticator = None
if api_settings.UNAUTHENTICATED_USER:
self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户
else:
self.user = Noneif api_settings.UNAUTHENTICATED_TOKEN: self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默认值为:None else: self.auth = None (user,token)表示验证通过并设置用户名和Token; AuthenticationFailed异常 </span><span style="color: #800000;">"""</span><span style="color: #000000;"> val </span>= request.query_params.get(<span style="color: #800000;">'</span><span style="color: #800000;">token</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">if</span> val <span style="color: #0000ff;">not</span> <span style="color: #0000ff;">in</span><span style="color: #000000;"> token_list: </span><span style="color: #0000ff;">raise</span> exceptions.AuthenticationFailed(<span style="color: #800000;">"</span><span style="color: #800000;">用户认证失败</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">return</span> (<span style="color: #800000;">'</span><span style="color: #800000;">登录用户</span><span style="color: #800000;">'</span>, <span style="color: #800000;">'</span><span style="color: #800000;">用户token</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> authenticate_header(self, request): </span><span style="color: #800000;">"""</span><span style="color: #800000;"> Return a string to be used as the value of the `WWW-Authenticate` header in a `401 Unauthenticated` response, or `None` if the authentication scheme should return `403 Permission Denied` responses. </span><span style="color: #800000;">"""</span> <span style="color: #0000ff;">pass</span>
class TestView(APIView):
authentication_classes = [Test1Authentication, Test2Authentication]
permission_classes = []</span><span style="color: #0000ff;">def</span> get(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.user) </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.auth) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">GET请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> post(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> put(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">PUT请求,响应内容</span><span style="color: #800000;">'</span>)</pre>
d. 认证和权限
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [
url(r'^test/', TestView.as_view()),
]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.authentication import BaseAuthentication from rest_framework.permissions import BasePermissionfrom rest_framework.request import Request
from rest_framework import exceptionstoken_list = [
'sfsfss123kuf3j123',
'asijnfowerkkf9812',
]class TestAuthentication(BaseAuthentication):
def authenticate(self, request):
"""
用户认证,如果验证成功后返回元组: (用户,用户Token)
:param request:
:return:
None,表示跳过该验证;
如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
self._authenticator = None
if api_settings.UNAUTHENTICATED_USER:
self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户
else:
self.user = Noneif api_settings.UNAUTHENTICATED_TOKEN: self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默认值为:None else: self.auth = None (user,token)表示验证通过并设置用户名和Token; AuthenticationFailed异常 </span><span style="color: #800000;">"""</span><span style="color: #000000;"> val </span>= request.query_params.get(<span style="color: #800000;">'</span><span style="color: #800000;">token</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">if</span> val <span style="color: #0000ff;">not</span> <span style="color: #0000ff;">in</span><span style="color: #000000;"> token_list: </span><span style="color: #0000ff;">raise</span> exceptions.AuthenticationFailed(<span style="color: #800000;">"</span><span style="color: #800000;">用户认证失败</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">return</span> (<span style="color: #800000;">'</span><span style="color: #800000;">登录用户</span><span style="color: #800000;">'</span>, <span style="color: #800000;">'</span><span style="color: #800000;">用户token</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> authenticate_header(self, request): </span><span style="color: #800000;">"""</span><span style="color: #800000;"> Return a string to be used as the value of the `WWW-Authenticate` header in a `401 Unauthenticated` response, or `None` if the authentication scheme should return `403 Permission Denied` responses. </span><span style="color: #800000;">"""</span> <span style="color: #0000ff;">pass</span>
class TestPermission(BasePermission):
message = "权限验证失败"<span style="color: #0000ff;">def</span><span style="color: #000000;"> has_permission(self, request, view): </span><span style="color: #800000;">"""</span><span style="color: #800000;"> 判断是否有权限访问当前请求 Return `True` if permission is granted, `False` otherwise. :param request: :param view: :return: True有权限;False无权限 </span><span style="color: #800000;">"""</span> <span style="color: #0000ff;">if</span> request.user == <span style="color: #800000;">"</span><span style="color: #800000;">管理员</span><span style="color: #800000;">"</span><span style="color: #000000;">: </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> True </span><span style="color: #008000;">#</span><span style="color: #008000;"> GenericAPIView中get_object时调用</span> <span style="color: #0000ff;">def</span><span style="color: #000000;"> has_object_permission(self, request, view, obj): </span><span style="color: #800000;">"""</span><span style="color: #800000;"> 视图继承GenericAPIView,并在其中使用get_object时获取对象时,触发单独对象权限验证 Return `True` if permission is granted, `False` otherwise. :param request: :param view: :param obj: :return: True有权限;False无权限 </span><span style="color: #800000;">"""</span> <span style="color: #0000ff;">if</span> request.user == <span style="color: #800000;">"</span><span style="color: #800000;">管理员</span><span style="color: #800000;">"</span><span style="color: #000000;">: </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> True
class TestView(APIView):
# 认证的动作是由request.user触发
authentication_classes = [TestAuthentication, ]</span><span style="color: #008000;">#</span><span style="color: #008000;"> 权限</span> <span style="color: #008000;">#</span><span style="color: #008000;"> 循环执行所有的权限</span> permission_classes =<span style="color: #000000;"> [TestPermission, ] </span><span style="color: #0000ff;">def</span> get(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #008000;">#</span><span style="color: #008000;"> self.dispatch</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.user) </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.auth) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">GET请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> post(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> put(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">PUT请求,响应内容</span><span style="color: #800000;">'</span>)</pre>
e. 全局使用
上述操作中均是对单独视图进行特殊配置,如果想要对全局进行配置,则需要再配置文件中写入即可。
REST_FRAMEWORK = { 'UNAUTHENTICATED_USER': None, 'UNAUTHENTICATED_TOKEN': None, "DEFAULT_AUTHENTICATION_CLASSES": [ "web.utils.TestAuthentication", ], "DEFAULT_PERMISSION_CLASSES": [ "web.utils.TestPermission", ], }
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [
url(r'^test/', TestView.as_view()),
]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Responseclass TestView(APIView):
</span><span style="color: #0000ff;">def</span> get(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #008000;">#</span><span style="color: #008000;"> self.dispatch</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.user) </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.auth) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">GET请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> post(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> put(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">PUT请求,响应内容</span><span style="color: #800000;">'</span>)</pre>
3. 用户访问次数/频率限制
a. 基于用户IP限制访问频率
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [
url(r'^test/', TestView.as_view()),
]
#!/usr/bin/env python # -*- coding:utf-8 -*- import time from rest_framework.views import APIView from rest_framework.response import Responsefrom rest_framework import exceptions
from rest_framework.throttling import BaseThrottle
from rest_framework.settings import api_settings# 保存访问记录
RECORD = {
'用户IP': [12312139, 12312135, 12312133, ]
}class TestThrottle(BaseThrottle):
ctime = time.time</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> get_ident(self, request): </span><span style="color: #800000;">"""</span><span style="color: #800000;"> 根据用户IP和代理IP,当做请求者的唯一IP Identify the machine making the request by parsing HTTP_X_FORWARDED_FOR if present and number of proxies is > 0. If not use all of HTTP_X_FORWARDED_FOR if it is available, if not use REMOTE_ADDR. </span><span style="color: #800000;">"""</span><span style="color: #000000;"> xff </span>= request.META.get(<span style="color: #800000;">'</span><span style="color: #800000;">HTTP_X_FORWARDED_FOR</span><span style="color: #800000;">'</span><span style="color: #000000;">) remote_addr </span>= request.META.get(<span style="color: #800000;">'</span><span style="color: #800000;">REMOTE_ADDR</span><span style="color: #800000;">'</span><span style="color: #000000;">) num_proxies </span>=<span style="color: #000000;"> api_settings.NUM_PROXIES </span><span style="color: #0000ff;">if</span> num_proxies <span style="color: #0000ff;">is</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> None: </span><span style="color: #0000ff;">if</span> num_proxies == 0 <span style="color: #0000ff;">or</span> xff <span style="color: #0000ff;">is</span><span style="color: #000000;"> None: </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> remote_addr addrs </span>= xff.split(<span style="color: #800000;">'</span><span style="color: #800000;">,</span><span style="color: #800000;">'</span><span style="color: #000000;">) client_addr </span>= addrs[-<span style="color: #000000;">min(num_proxies, len(addrs))] </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> client_addr.strip() </span><span style="color: #0000ff;">return</span> <span style="color: #800000;">''</span>.join(xff.split()) <span style="color: #0000ff;">if</span> xff <span style="color: #0000ff;">else</span><span style="color: #000000;"> remote_addr </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> allow_request(self, request, view): </span><span style="color: #800000;">"""</span><span style="color: #800000;"> 是否仍然在允许范围内 Return `True` if the request should be allowed, `False` otherwise. :param request: :param view: :return: True,表示可以通过;False表示已超过限制,不允许访问 </span><span style="color: #800000;">"""</span> <span style="color: #008000;">#</span><span style="color: #008000;"> 获取用户唯一标识(如:IP)</span> <span style="color: #008000;">#</span><span style="color: #008000;"> 允许一分钟访问10次</span> num_request = 10<span style="color: #000000;"> time_request </span>= 60<span style="color: #000000;"> now </span>=<span style="color: #000000;"> self.ctime() ident </span>=<span style="color: #000000;"> self.get_ident(request) self.ident </span>=<span style="color: #000000;"> ident </span><span style="color: #0000ff;">if</span> ident <span style="color: #0000ff;">not</span> <span style="color: #0000ff;">in</span><span style="color: #000000;"> RECORD: RECORD[ident] </span>=<span style="color: #000000;"> [now, ] </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> True history </span>=<span style="color: #000000;"> RECORD[ident] </span><span style="color: #0000ff;">while</span> history <span style="color: #0000ff;">and</span> history[-1] <= now -<span style="color: #000000;"> time_request: history.pop() </span><span style="color: #0000ff;">if</span> len(history) <<span style="color: #000000;"> num_request: history.insert(0, now) </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> True </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> wait(self): </span><span style="color: #800000;">"""</span><span style="color: #800000;"> 多少秒后可以允许继续访问 Optionally, return a recommended number of seconds to wait before the next request. </span><span style="color: #800000;">"""</span><span style="color: #000000;"> last_time </span>=<span style="color: #000000;"> RECORD[self.ident][0] now </span>=<span style="color: #000000;"> self.ctime() </span><span style="color: #0000ff;">return</span> int(60 + last_time -<span style="color: #000000;"> now)
class TestView(APIView):
throttle_classes = [TestThrottle, ]</span><span style="color: #0000ff;">def</span> get(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #008000;">#</span><span style="color: #008000;"> self.dispatch</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.user) </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.auth) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">GET请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> post(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> put(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">PUT请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> throttled(self, request, wait): </span><span style="color: #800000;">"""</span><span style="color: #800000;"> 访问次数被限制时,定制错误信息 </span><span style="color: #800000;">"""</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> Throttled(exceptions.Throttled): default_detail </span>= <span style="color: #800000;">'</span><span style="color: #800000;">请求被限制.</span><span style="color: #800000;">'</span><span style="color: #000000;"> extra_detail_singular </span>= <span style="color: #800000;">'</span><span style="color: #800000;">请 {wait} 秒之后再重试.</span><span style="color: #800000;">'</span><span style="color: #000000;"> extra_detail_plural </span>= <span style="color: #800000;">'</span><span style="color: #800000;">请 {wait} 秒之后再重试.</span><span style="color: #800000;">'</span> <span style="color: #0000ff;">raise</span> Throttled(wait)</pre>
b. 基于用户IP显示访问频率(利于Django缓存)
REST_FRAMEWORK = { 'DEFAULT_THROTTLE_RATES': { 'test_scope': '10/m', }, }
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [
url(r'^test/', TestView.as_view()),
]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Responsefrom rest_framework import exceptions
from rest_framework.throttling import SimpleRateThrottleclass TestThrottle(SimpleRateThrottle):
</span><span style="color: #008000;">#</span><span style="color: #008000;"> 配置文件定义的显示频率的Key</span> scope = <span style="color: #800000;">"</span><span style="color: #800000;">test_scope</span><span style="color: #800000;">"</span> <span style="color: #0000ff;">def</span><span style="color: #000000;"> get_cache_key(self, request, view): </span><span style="color: #800000;">"""</span><span style="color: #800000;"> Should return a unique cache-key which can be used for throttling. Must be overridden. May return `None` if the request should not be throttled. </span><span style="color: #800000;">"""</span> <span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> request.user: ident </span>=<span style="color: #000000;"> self.get_ident(request) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: ident </span>=<span style="color: #000000;"> request.user </span><span style="color: #0000ff;">return</span> self.cache_format %<span style="color: #000000;"> { </span><span style="color: #800000;">'</span><span style="color: #800000;">scope</span><span style="color: #800000;">'</span><span style="color: #000000;">: self.scope, </span><span style="color: #800000;">'</span><span style="color: #800000;">ident</span><span style="color: #800000;">'</span><span style="color: #000000;">: ident }
class TestView(APIView):
throttle_classes = [TestThrottle, ]</span><span style="color: #0000ff;">def</span> get(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #008000;">#</span><span style="color: #008000;"> self.dispatch</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.user) </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.auth) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">GET请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> post(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> put(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">PUT请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> throttled(self, request, wait): </span><span style="color: #800000;">"""</span><span style="color: #800000;"> 访问次数被限制时,定制错误信息 </span><span style="color: #800000;">"""</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> Throttled(exceptions.Throttled): default_detail </span>= <span style="color: #800000;">'</span><span style="color: #800000;">请求被限制.</span><span style="color: #800000;">'</span><span style="color: #000000;"> extra_detail_singular </span>= <span style="color: #800000;">'</span><span style="color: #800000;">请 {wait} 秒之后再重试.</span><span style="color: #800000;">'</span><span style="color: #000000;"> extra_detail_plural </span>= <span style="color: #800000;">'</span><span style="color: #800000;">请 {wait} 秒之后再重试.</span><span style="color: #800000;">'</span> <span style="color: #0000ff;">raise</span> Throttled(wait)</pre>
c. view中限制请求频率
REST_FRAMEWORK = { 'DEFAULT_THROTTLE_RATES': { 'xxxxxx': '10/m', }, }
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [
url(r'^test/', TestView.as_view()),
]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Responsefrom rest_framework import exceptions
from rest_framework.throttling import ScopedRateThrottle# 继承 ScopedRateThrottle
class TestThrottle(ScopedRateThrottle):</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> get_cache_key(self, request, view): </span><span style="color: #800000;">"""</span><span style="color: #800000;"> Should return a unique cache-key which can be used for throttling. Must be overridden. May return `None` if the request should not be throttled. </span><span style="color: #800000;">"""</span> <span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> request.user: ident </span>=<span style="color: #000000;"> self.get_ident(request) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: ident </span>=<span style="color: #000000;"> request.user </span><span style="color: #0000ff;">return</span> self.cache_format %<span style="color: #000000;"> { </span><span style="color: #800000;">'</span><span style="color: #800000;">scope</span><span style="color: #800000;">'</span><span style="color: #000000;">: self.scope, </span><span style="color: #800000;">'</span><span style="color: #800000;">ident</span><span style="color: #800000;">'</span><span style="color: #000000;">: ident }
class TestView(APIView):
throttle_classes = [TestThrottle, ]</span><span style="color: #008000;">#</span><span style="color: #008000;"> 在settings中获取 xxxxxx 对应的频率限制值</span> throttle_scope = <span style="color: #800000;">"</span><span style="color: #800000;">xxxxxx</span><span style="color: #800000;">"</span> <span style="color: #0000ff;">def</span> get(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #008000;">#</span><span style="color: #008000;"> self.dispatch</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.user) </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.auth) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">GET请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> post(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> put(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">PUT请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> throttled(self, request, wait): </span><span style="color: #800000;">"""</span><span style="color: #800000;"> 访问次数被限制时,定制错误信息 </span><span style="color: #800000;">"""</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> Throttled(exceptions.Throttled): default_detail </span>= <span style="color: #800000;">'</span><span style="color: #800000;">请求被限制.</span><span style="color: #800000;">'</span><span style="color: #000000;"> extra_detail_singular </span>= <span style="color: #800000;">'</span><span style="color: #800000;">请 {wait} 秒之后再重试.</span><span style="color: #800000;">'</span><span style="color: #000000;"> extra_detail_plural </span>= <span style="color: #800000;">'</span><span style="color: #800000;">请 {wait} 秒之后再重试.</span><span style="color: #800000;">'</span> <span style="color: #0000ff;">raise</span> Throttled(wait)</pre>
d. 匿名时用IP限制+登录时用Token限制
REST_FRAMEWORK = { 'UNAUTHENTICATED_USER': None, 'UNAUTHENTICATED_TOKEN': None, 'DEFAULT_THROTTLE_RATES': { 'luffy_anon': '10/m', 'luffy_user': '20/m', }, }
from django.conf.urls import url, include from web.views.s3_throttling import TestViewurlpatterns = [
url(r'^test/', TestView.as_view()),
]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Responsefrom rest_framework.throttling import SimpleRateThrottle
class LuffyAnonRateThrottle(SimpleRateThrottle):
"""
匿名用户,根据IP进行限制
"""
scope = "luffy_anon"<span style="color: #0000ff;">def</span><span style="color: #000000;"> get_cache_key(self, request, view): </span><span style="color: #008000;">#</span><span style="color: #008000;"> 用户已登录,则跳过 匿名频率限制</span> <span style="color: #0000ff;">if</span><span style="color: #000000;"> request.user: </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> None </span><span style="color: #0000ff;">return</span> self.cache_format %<span style="color: #000000;"> { </span><span style="color: #800000;">'</span><span style="color: #800000;">scope</span><span style="color: #800000;">'</span><span style="color: #000000;">: self.scope, </span><span style="color: #800000;">'</span><span style="color: #800000;">ident</span><span style="color: #800000;">'</span><span style="color: #000000;">: self.get_ident(request) }
class LuffyUserRateThrottle(SimpleRateThrottle):
"""
登录用户,根据用户token限制
"""
scope = "luffy_user"<span style="color: #0000ff;">def</span><span style="color: #000000;"> get_ident(self, request): </span><span style="color: #800000;">"""</span><span style="color: #800000;"> 认证成功时:request.user是用户对象;request.auth是token对象 :param request: :return: </span><span style="color: #800000;">"""</span> <span style="color: #008000;">#</span><span style="color: #008000;"> return request.auth.token</span> <span style="color: #0000ff;">return</span> <span style="color: #800000;">"</span><span style="color: #800000;">user_token</span><span style="color: #800000;">"</span> <span style="color: #0000ff;">def</span><span style="color: #000000;"> get_cache_key(self, request, view): </span><span style="color: #800000;">"""</span><span style="color: #800000;"> 获取缓存key :param request: :param view: :return: </span><span style="color: #800000;">"""</span> <span style="color: #008000;">#</span><span style="color: #008000;"> 未登录用户,则跳过 Token限制</span> <span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> request.user: </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> None </span><span style="color: #0000ff;">return</span> self.cache_format %<span style="color: #000000;"> { </span><span style="color: #800000;">'</span><span style="color: #800000;">scope</span><span style="color: #800000;">'</span><span style="color: #000000;">: self.scope, </span><span style="color: #800000;">'</span><span style="color: #800000;">ident</span><span style="color: #800000;">'</span><span style="color: #000000;">: self.get_ident(request) }
class TestView(APIView):
throttle_classes = [LuffyUserRateThrottle, LuffyAnonRateThrottle, ]</span><span style="color: #0000ff;">def</span> get(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #008000;">#</span><span style="color: #008000;"> self.dispatch</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.user) </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.auth) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">GET请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> post(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> put(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">PUT请求,响应内容</span><span style="color: #800000;">'</span>)</pre>
e. 全局使用
REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES': [ 'api.utils.throttles.throttles.LuffyAnonRateThrottle', 'api.utils.throttles.throttles.LuffyUserRateThrottle', ], 'DEFAULT_THROTTLE_RATES': { 'anon': '10/day', 'user': '10/day', 'luffy_anon': '10/m', 'luffy_user': '20/m', }, }
4. 版本
a. 基于url的get传参方式
如:/users?version=v1
REST_FRAMEWORK = { 'DEFAULT_VERSION': 'v1', # 默认版本 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本 'VERSION_PARAM': 'version' # URL中获取值的key }
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [
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.versioning import QueryParameterVersioningclass TestView(APIView):
versioning_class = QueryParameterVersioning</span><span style="color: #0000ff;">def</span> get(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #008000;">#</span><span style="color: #008000;"> 获取版本</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.version) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 获取版本管理的类</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.versioning_scheme) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 反向生成URL</span> reverse_url = request.versioning_scheme.reverse(<span style="color: #800000;">'</span><span style="color: #800000;">test</span><span style="color: #800000;">'</span>, request=<span style="color: #000000;">request) </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(reverse_url) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">GET请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> post(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> put(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">PUT请求,响应内容</span><span style="color: #800000;">'</span>)</pre>
b. 基于url的正则方式
如:/v1/users/
REST_FRAMEWORK = { 'DEFAULT_VERSION': 'v1', # 默认版本 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本 'VERSION_PARAM': 'version' # URL中获取值的key }
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [
url(r'^(?P<version>[v1|v2]+)/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.versioning import URLPathVersioningclass TestView(APIView):
versioning_class = URLPathVersioning</span><span style="color: #0000ff;">def</span> get(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #008000;">#</span><span style="color: #008000;"> 获取版本</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.version) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 获取版本管理的类</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.versioning_scheme) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 反向生成URL</span> reverse_url = request.versioning_scheme.reverse(<span style="color: #800000;">'</span><span style="color: #800000;">test</span><span style="color: #800000;">'</span>, request=<span style="color: #000000;">request) </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(reverse_url) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">GET请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> post(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> put(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">PUT请求,响应内容</span><span style="color: #800000;">'</span>)</pre>
c. 基于 accept 请求头方式
如:Accept: application/json; version=1.0
REST_FRAMEWORK = { 'DEFAULT_VERSION': 'v1', # 默认版本 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本 'VERSION_PARAM': 'version' # URL中获取值的key }
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [
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.versioning import AcceptHeaderVersioningclass TestView(APIView):
versioning_class = AcceptHeaderVersioning</span><span style="color: #0000ff;">def</span> get(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #008000;">#</span><span style="color: #008000;"> 获取版本 HTTP_ACCEPT头</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.version) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 获取版本管理的类</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.versioning_scheme) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 反向生成URL</span> reverse_url = request.versioning_scheme.reverse(<span style="color: #800000;">'</span><span style="color: #800000;">test</span><span style="color: #800000;">'</span>, request=<span style="color: #000000;">request) </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(reverse_url) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">GET请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> post(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> put(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">PUT请求,响应内容</span><span style="color: #800000;">'</span>)</pre>
d. 基于主机名方法
如:v1.example.com
ALLOWED_HOSTS = ['*'] REST_FRAMEWORK = { 'DEFAULT_VERSION': 'v1', # 默认版本 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本 'VERSION_PARAM': 'version' # URL中获取值的key }
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [
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.versioning import HostNameVersioningclass TestView(APIView):
versioning_class = HostNameVersioning</span><span style="color: #0000ff;">def</span> get(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #008000;">#</span><span style="color: #008000;"> 获取版本</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.version) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 获取版本管理的类</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.versioning_scheme) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 反向生成URL</span> reverse_url = request.versioning_scheme.reverse(<span style="color: #800000;">'</span><span style="color: #800000;">test</span><span style="color: #800000;">'</span>, request=<span style="color: #000000;">request) </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(reverse_url) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">GET请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> post(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> put(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">PUT请求,响应内容</span><span style="color: #800000;">'</span>)</pre>
e. 基于django路由系统的namespace
如:example.com/v1/users/
REST_FRAMEWORK = { 'DEFAULT_VERSION': 'v1', # 默认版本 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本 'VERSION_PARAM': 'version' # URL中获取值的key }
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [
url(r'^v1/', ([
url(r'test/', TestView.as_view(), name='test'),
], None, 'v1')),
url(r'^v2/', ([
url(r'test/', TestView.as_view(), name='test'),
], None, 'v2')),]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.versioning import NamespaceVersioningclass TestView(APIView):
versioning_class = NamespaceVersioning</span><span style="color: #0000ff;">def</span> get(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #008000;">#</span><span style="color: #008000;"> 获取版本</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.version) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 获取版本管理的类</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.versioning_scheme) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 反向生成URL</span> reverse_url = request.versioning_scheme.reverse(<span style="color: #800000;">'</span><span style="color: #800000;">test</span><span style="color: #800000;">'</span>, request=<span style="color: #000000;">request) </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(reverse_url) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">GET请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> post(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> put(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">PUT请求,响应内容</span><span style="color: #800000;">'</span>)</pre>
f. 全局使用
REST_FRAMEWORK = { 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning", 'DEFAULT_VERSION': 'v1', 'ALLOWED_VERSIONS': ['v1', 'v2'], 'VERSION_PARAM': 'version' }
5. 解析器(parser)
根据请求头 content-type 选择对应的解析器就请求体内容进行处理。
a. 仅处理请求头content-type为application/json的请求体
from django.conf.urls import url, include from web.views.s5_parser import TestViewurlpatterns = [
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 JSONParserclass TestView(APIView):
parser_classes = [JSONParser, ]</span><span style="color: #0000ff;">def</span> post(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.content_type) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 获取请求的值,并使用对应的JSONParser进行处理</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.data) </span><span style="color: #008000;">#</span><span style="color: #008000;"> application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.POST) </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.FILES) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> put(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">PUT请求,响应内容</span><span style="color: #800000;">'</span>)</pre>
b. 仅处理请求头content-type为application/x-www-form-urlencoded 的请求体
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [
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 FormParserclass TestView(APIView):
parser_classes = [FormParser, ]</span><span style="color: #0000ff;">def</span> post(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.content_type) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 获取请求的值,并使用对应的JSONParser进行处理</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.data) </span><span style="color: #008000;">#</span><span style="color: #008000;"> application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.POST) </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.FILES) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> put(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">PUT请求,响应内容</span><span style="color: #800000;">'</span>)</pre>
c. 仅处理请求头content-type为multipart/form-data的请求体
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [
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 MultiPartParserclass TestView(APIView):
parser_classes = [MultiPartParser, ]</span><span style="color: #0000ff;">def</span> post(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.content_type) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 获取请求的值,并使用对应的JSONParser进行处理</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.data) </span><span style="color: #008000;">#</span><span style="color: #008000;"> application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.POST) </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.FILES) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> put(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">PUT请求,响应内容</span><span style="color: #800000;">'</span>)</pre>
<!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=<span style="color: #800000;">"</span><span style="color: #800000;">submit</span><span style="color: #800000;">"</span> value=<span style="color: #800000;">"</span><span style="color: #800000;">提交</span><span style="color: #800000;">"</span>>
</form>
</body>
</html>
d. 仅上传文件
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [
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 FileUploadParserclass TestView(APIView):
parser_classes = [FileUploadParser, ]</span><span style="color: #0000ff;">def</span> post(self, request, filename, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(filename) </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.content_type) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 获取请求的值,并使用对应的JSONParser进行处理</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.data) </span><span style="color: #008000;">#</span><span style="color: #008000;"> application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.POST) </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.FILES) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> put(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">PUT请求,响应内容</span><span style="color: #800000;">'</span>)</pre>
<!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=<span style="color: #800000;">"</span><span style="color: #800000;">submit</span><span style="color: #800000;">"</span> value=<span style="color: #800000;">"</span><span style="color: #800000;">提交</span><span style="color: #800000;">"</span>>
</form>
</body>
</html>
e. 同时多个Parser
当同时使用多个parser时,rest framework会根据请求头content-type自动进行比对,并使用对应parser
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [
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, MultiPartParserclass TestView(APIView):
parser_classes = [JSONParser, FormParser, MultiPartParser, ]</span><span style="color: #0000ff;">def</span> post(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.content_type) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 获取请求的值,并使用对应的JSONParser进行处理</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.data) </span><span style="color: #008000;">#</span><span style="color: #008000;"> application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.POST) </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.FILES) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> put(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">PUT请求,响应内容</span><span style="color: #800000;">'</span>)</pre>
f. 全局使用
REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES':[ 'rest_framework.parsers.JSONParser' 'rest_framework.parsers.FormParser' 'rest_framework.parsers.MultiPartParser' ]}
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [
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 Responseclass TestView(APIView):
def post(self, request, *args, **kwargs):
print(request.content_type)</span><span style="color: #008000;">#</span><span style="color: #008000;"> 获取请求的值,并使用对应的JSONParser进行处理</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.data) </span><span style="color: #008000;">#</span><span style="color: #008000;"> application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.POST) </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(request.FILES) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span> put(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">PUT请求,响应内容</span><span style="color: #800000;">'</span>)</pre>
注意:个别特殊的值可以通过Django的request对象 request._request 来进行获取
6. 序列化
序列化用于对用户请求数据进行验证和数据进行序列化。
a. 自定义字段
from django.conf.urls import url, include from web.views.s6_serializers import TestViewurlpatterns = [
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 import serializers from .. import modelsclass PasswordValidator(object):
def init(self, base):
self.base = base</span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__call__</span><span style="color: #000000;">(self, value): </span><span style="color: #0000ff;">if</span> value !=<span style="color: #000000;"> self.base: message </span>= <span style="color: #800000;">'</span><span style="color: #800000;">This field must be %s.</span><span style="color: #800000;">'</span> %<span style="color: #000000;"> self.base </span><span style="color: #0000ff;">raise</span><span style="color: #000000;"> serializers.ValidationError(message) </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> set_context(self, serializer_field): </span><span style="color: #800000;">"""</span><span style="color: #800000;"> This hook is called by the serializer instance, prior to the validation call being made. </span><span style="color: #800000;">"""</span> <span style="color: #008000;">#</span><span style="color: #008000;"> 执行验证之前调用,serializer_fields是当前字段对象</span> <span style="color: #0000ff;">pass</span>
class UserSerializer(serializers.Serializer):
ut_title = serializers.CharField(source='ut.title')
user = serializers.CharField(min_length=6)
pwd = serializers.CharField(error_messages={'required': '密码不能为空'}, validators=[PasswordValidator('666')])class TestView(APIView):
def get(self, request, *args, **kwargs):</span><span style="color: #008000;">#</span><span style="color: #008000;"> 序列化,将数据库查询字段序列化为字典</span> data_list =<span style="color: #000000;"> models.UserInfo.objects.all() ser </span>= UserSerializer(instance=data_list, many=<span style="color: #000000;">True) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 或</span> <span style="color: #008000;">#</span><span style="color: #008000;"> obj = models.UserInfo.objects.all().first()</span> <span style="color: #008000;">#</span><span style="color: #008000;"> ser = UserSerializer(instance=obj, many=False)</span> <span style="color: #0000ff;">return</span><span style="color: #000000;"> Response(ser.data) </span><span style="color: #0000ff;">def</span> post(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #008000;">#</span><span style="color: #008000;"> 验证,对请求发来的数据进行验证</span> ser = UserSerializer(data=<span style="color: #000000;">request.data) </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> ser.is_valid(): </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(ser.validated_data) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(ser.errors) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span>)</pre>
b. 基于Model自动生成字段
from django.conf.urls import url, include from web.views.s6_serializers import TestViewurlpatterns = [
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 import serializers from .. import modelsclass PasswordValidator(object):
def init(self, base):
self.base = str(base)</span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__call__</span><span style="color: #000000;">(self, value): </span><span style="color: #0000ff;">if</span> value !=<span style="color: #000000;"> self.base: message </span>= <span style="color: #800000;">'</span><span style="color: #800000;">This field must be %s.</span><span style="color: #800000;">'</span> %<span style="color: #000000;"> self.base </span><span style="color: #0000ff;">raise</span><span style="color: #000000;"> serializers.ValidationError(message) </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> set_context(self, serializer_field): </span><span style="color: #800000;">"""</span><span style="color: #800000;"> This hook is called by the serializer instance, prior to the validation call being made. </span><span style="color: #800000;">"""</span> <span style="color: #008000;">#</span><span style="color: #008000;"> 执行验证之前调用,serializer_fields是当前字段对象</span> <span style="color: #0000ff;">pass</span>
class ModelUserSerializer(serializers.ModelSerializer):
user </span>= serializers.CharField(max_length=32<span style="color: #000000;">) </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> Meta: model </span>=<span style="color: #000000;"> models.UserInfo fields </span>= <span style="color: #800000;">"</span><span style="color: #800000;">__all__</span><span style="color: #800000;">"</span> <span style="color: #008000;">#</span><span style="color: #008000;"> fields = ['user', 'pwd', 'ut']</span> depth = 2<span style="color: #000000;"> extra_kwargs </span>= {<span style="color: #800000;">'</span><span style="color: #800000;">user</span><span style="color: #800000;">'</span>: {<span style="color: #800000;">'</span><span style="color: #800000;">min_length</span><span style="color: #800000;">'</span>: 6}, <span style="color: #800000;">'</span><span style="color: #800000;">pwd</span><span style="color: #800000;">'</span>: {<span style="color: #800000;">'</span><span style="color: #800000;">validators</span><span style="color: #800000;">'</span>: [PasswordValidator(666<span style="color: #000000;">), ]}} </span><span style="color: #008000;">#</span><span style="color: #008000;"> read_only_fields = ['user']</span>
class TestView(APIView):
def get(self, request, *args, **kwargs):</span><span style="color: #008000;">#</span><span style="color: #008000;"> 序列化,将数据库查询字段序列化为字典</span> data_list =<span style="color: #000000;"> models.UserInfo.objects.all() ser </span>= ModelUserSerializer(instance=data_list, many=<span style="color: #000000;">True) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 或</span> <span style="color: #008000;">#</span><span style="color: #008000;"> obj = models.UserInfo.objects.all().first()</span> <span style="color: #008000;">#</span><span style="color: #008000;"> ser = UserSerializer(instance=obj, many=False)</span> <span style="color: #0000ff;">return</span><span style="color: #000000;"> Response(ser.data) </span><span style="color: #0000ff;">def</span> post(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #008000;">#</span><span style="color: #008000;"> 验证,对请求发来的数据进行验证</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.data) ser </span>= ModelUserSerializer(data=<span style="color: #000000;">request.data) </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> ser.is_valid(): </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(ser.validated_data) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(ser.errors) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span>)</pre>
c. 生成URL
from django.conf.urls import url, include from web.views.s6_serializers import TestViewurlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
url(r'detail/(?P<pk>\d+)/', TestView.as_view(), name='detail'),
]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializers from .. import modelsclass PasswordValidator(object):
def init(self, base):
self.base = str(base)</span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__call__</span><span style="color: #000000;">(self, value): </span><span style="color: #0000ff;">if</span> value !=<span style="color: #000000;"> self.base: message </span>= <span style="color: #800000;">'</span><span style="color: #800000;">This field must be %s.</span><span style="color: #800000;">'</span> %<span style="color: #000000;"> self.base </span><span style="color: #0000ff;">raise</span><span style="color: #000000;"> serializers.ValidationError(message) </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> set_context(self, serializer_field): </span><span style="color: #800000;">"""</span><span style="color: #800000;"> This hook is called by the serializer instance, prior to the validation call being made. </span><span style="color: #800000;">"""</span> <span style="color: #008000;">#</span><span style="color: #008000;"> 执行验证之前调用,serializer_fields是当前字段对象</span> <span style="color: #0000ff;">pass</span>
class ModelUserSerializer(serializers.ModelSerializer):
ut = serializers.HyperlinkedIdentityField(view_name='detail')
class Meta:
model = models.UserInfo
fields = "all"extra_kwargs </span>=<span style="color: #000000;"> { </span><span style="color: #800000;">'</span><span style="color: #800000;">user</span><span style="color: #800000;">'</span>: {<span style="color: #800000;">'</span><span style="color: #800000;">min_length</span><span style="color: #800000;">'</span>: 6<span style="color: #000000;">}, </span><span style="color: #800000;">'</span><span style="color: #800000;">pwd</span><span style="color: #800000;">'</span>: {<span style="color: #800000;">'</span><span style="color: #800000;">validators</span><span style="color: #800000;">'</span>: [PasswordValidator(666<span style="color: #000000;">),]}, }
class TestView(APIView):
def get(self, request, *args, **kwargs):</span><span style="color: #008000;">#</span><span style="color: #008000;"> 序列化,将数据库查询字段序列化为字典</span> data_list =<span style="color: #000000;"> models.UserInfo.objects.all() ser </span>= ModelUserSerializer(instance=data_list, many=True, context={<span style="color: #800000;">'</span><span style="color: #800000;">request</span><span style="color: #800000;">'</span><span style="color: #000000;">: request}) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 或</span> <span style="color: #008000;">#</span><span style="color: #008000;"> obj = models.UserInfo.objects.all().first()</span> <span style="color: #008000;">#</span><span style="color: #008000;"> ser = UserSerializer(instance=obj, many=False)</span> <span style="color: #0000ff;">return</span><span style="color: #000000;"> Response(ser.data) </span><span style="color: #0000ff;">def</span> post(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #008000;">#</span><span style="color: #008000;"> 验证,对请求发来的数据进行验证</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.data) ser </span>= ModelUserSerializer(data=<span style="color: #000000;">request.data) </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> ser.is_valid(): </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(ser.validated_data) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(ser.errors) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span>)</pre>
d. 自动生成URL
from django.conf.urls import url, include from web.views.s6_serializers import TestViewurlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
url(r'detail/(?P<pk>\d+)/', TestView.as_view(), name='xxxx'),
]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializers from .. import modelsclass PasswordValidator(object):
def init(self, base):
self.base = str(base)</span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__call__</span><span style="color: #000000;">(self, value): </span><span style="color: #0000ff;">if</span> value !=<span style="color: #000000;"> self.base: message </span>= <span style="color: #800000;">'</span><span style="color: #800000;">This field must be %s.</span><span style="color: #800000;">'</span> %<span style="color: #000000;"> self.base </span><span style="color: #0000ff;">raise</span><span style="color: #000000;"> serializers.ValidationError(message) </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> set_context(self, serializer_field): </span><span style="color: #800000;">"""</span><span style="color: #800000;"> This hook is called by the serializer instance, prior to the validation call being made. </span><span style="color: #800000;">"""</span> <span style="color: #008000;">#</span><span style="color: #008000;"> 执行验证之前调用,serializer_fields是当前字段对象</span> <span style="color: #0000ff;">pass</span>
class ModelUserSerializer(serializers.HyperlinkedModelSerializer):
ll = serializers.HyperlinkedIdentityField(view_name='xxxx')
tt = serializers.CharField(required=False)</span><span style="color: #0000ff;">class</span><span style="color: #000000;"> Meta: model </span>=<span style="color: #000000;"> models.UserInfo fields </span>= <span style="color: #800000;">"</span><span style="color: #800000;">__all__</span><span style="color: #800000;">"</span><span style="color: #000000;"> list_serializer_class </span>=<span style="color: #000000;"> serializers.ListSerializer extra_kwargs </span>=<span style="color: #000000;"> { </span><span style="color: #800000;">'</span><span style="color: #800000;">user</span><span style="color: #800000;">'</span>: {<span style="color: #800000;">'</span><span style="color: #800000;">min_length</span><span style="color: #800000;">'</span>: 6<span style="color: #000000;">}, </span><span style="color: #800000;">'</span><span style="color: #800000;">pwd</span><span style="color: #800000;">'</span>: {<span style="color: #800000;">'</span><span style="color: #800000;">validators</span><span style="color: #800000;">'</span>: [PasswordValidator(666<span style="color: #000000;">), ]}, </span><span style="color: #800000;">'</span><span style="color: #800000;">url</span><span style="color: #800000;">'</span>: {<span style="color: #800000;">'</span><span style="color: #800000;">view_name</span><span style="color: #800000;">'</span>: <span style="color: #800000;">'</span><span style="color: #800000;">xxxx</span><span style="color: #800000;">'</span><span style="color: #000000;">}, </span><span style="color: #800000;">'</span><span style="color: #800000;">ut</span><span style="color: #800000;">'</span>: {<span style="color: #800000;">'</span><span style="color: #800000;">view_name</span><span style="color: #800000;">'</span>: <span style="color: #800000;">'</span><span style="color: #800000;">xxxx</span><span style="color: #800000;">'</span><span style="color: #000000;">}, }
class TestView(APIView):
def get(self, request, *args, **kwargs):
# # 序列化,将数据库查询字段序列化为字典
data_list = models.UserInfo.objects.all()
ser = ModelUserSerializer(instance=data_list, many=True, context={'request': request})
# # 如果Many=True
# # 或
# # obj = models.UserInfo.objects.all().first()
# # ser = UserSerializer(instance=obj, many=False)
return Response(ser.data)</span><span style="color: #0000ff;">def</span> post(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #008000;">#</span><span style="color: #008000;"> 验证,对请求发来的数据进行验证</span> <span style="color: #0000ff;">print</span><span style="color: #000000;">(request.data) ser </span>= ModelUserSerializer(data=<span style="color: #000000;">request.data) </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> ser.is_valid(): </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(ser.validated_data) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #0000ff;">print</span><span style="color: #000000;">(ser.errors) </span><span style="color: #0000ff;">return</span> Response(<span style="color: #800000;">'</span><span style="color: #800000;">POST请求,响应内容</span><span style="color: #800000;">'</span>)</pre>
7. 分页
a. 根据页码进行分页
from django.conf.urls import url, include from rest_framework import routers from web.views import s9_paginationurlpatterns = [
url(r'^test/', s9_pagination.UserViewSet.as_view()),
]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework import serializers from .. import modelsfrom rest_framework.pagination import PageNumberPagination
class StandardResultsSetPagination(PageNumberPagination):
# 默认每页显示的数据条数
page_size = 1
# 获取URL参数中设置的每页显示数据条数
page_size_query_param = 'page_size'<span style="color: #008000;">#</span><span style="color: #008000;"> 获取URL参数中传入的页码key</span> page_query_param = <span style="color: #800000;">'</span><span style="color: #800000;">page</span><span style="color: #800000;">'</span> <span style="color: #008000;">#</span><span style="color: #008000;"> 最大支持的每页显示的数据条数</span> max_page_size = 1
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "all"class UserViewSet(APIView):
def get(self, request, *args, **kwargs):
user_list = models.UserInfo.objects.all().order_by('-id')</span><span style="color: #008000;">#</span><span style="color: #008000;"> 实例化分页对象,获取数据库中的分页数据</span> paginator =<span style="color: #000000;"> StandardResultsSetPagination() page_user_list </span>= paginator.paginate_queryset(user_list, self.request, view=<span style="color: #000000;">self) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 序列化对象</span> serializer = UserSerializer(page_user_list, many=<span style="color: #000000;">True) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 生成分页和数据</span> response =<span style="color: #000000;"> paginator.get_paginated_response(serializer.data) </span><span style="color: #0000ff;">return</span> response</pre>
b. 位置和个数进行分页
from django.conf.urls import url, include from web.views import s9_paginationurlpatterns = [
url(r'^test/', s9_pagination.UserViewSet.as_view()),
]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework import serializers from .. import modelsfrom rest_framework.pagination import PageNumberPagination,LimitOffsetPagination
class StandardResultsSetPagination(LimitOffsetPagination):
# 默认每页显示的数据条数
default_limit = 10
# URL中传入的显示数据条数的参数
limit_query_param = 'limit'
# URL中传入的数据位置的参数
offset_query_param = 'offset'
# 最大每页显得条数
max_limit = Noneclass UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "all"class UserViewSet(APIView):
def get(self, request, *args, **kwargs):
user_list = models.UserInfo.objects.all().order_by('-id')</span><span style="color: #008000;">#</span><span style="color: #008000;"> 实例化分页对象,获取数据库中的分页数据</span> paginator =<span style="color: #000000;"> StandardResultsSetPagination() page_user_list </span>= paginator.paginate_queryset(user_list, self.request, view=<span style="color: #000000;">self) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 序列化对象</span> serializer = UserSerializer(page_user_list, many=<span style="color: #000000;">True) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 生成分页和数据</span> response =<span style="color: #000000;"> paginator.get_paginated_response(serializer.data) </span><span style="color: #0000ff;">return</span> response</pre>
c. 游标分页
from django.conf.urls import url, include from web.views import s9_paginationurlpatterns = [
url(r'^test/', s9_pagination.UserViewSet.as_view()),
]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework import serializers from .. import modelsfrom rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
class StandardResultsSetPagination(CursorPagination):
# URL传入的游标参数
cursor_query_param = 'cursor'
# 默认每页显示的数据条数
page_size = 2
# URL传入的每页显示条数的参数
page_size_query_param = 'page_size'
# 每页显示数据最大条数
max_page_size = 1000<span style="color: #008000;">#</span><span style="color: #008000;"> 根据ID从大到小排列</span> ordering = <span style="color: #800000;">"</span><span style="color: #800000;">id</span><span style="color: #800000;">"</span>
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "all"class UserViewSet(APIView):
def get(self, request, *args, **kwargs):
user_list = models.UserInfo.objects.all().order_by('-id')</span><span style="color: #008000;">#</span><span style="color: #008000;"> 实例化分页对象,获取数据库中的分页数据</span> paginator =<span style="color: #000000;"> StandardResultsSetPagination() page_user_list </span>= paginator.paginate_queryset(user_list, self.request, view=<span style="color: #000000;">self) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 序列化对象</span> serializer = UserSerializer(page_user_list, many=<span style="color: #000000;">True) </span><span style="color: #008000;">#</span><span style="color: #008000;"> 生成分页和数据</span> response =<span style="color: #000000;"> paginator.get_paginated_response(serializer.data) </span><span style="color: #0000ff;">return</span> response</pre>
8. 路由系统
a. 自定义路由
from django.conf.urls import url, include from web.views import s11_renderurlpatterns = [
url(r'^test/$', s11_render.TestView.as_view()),
url(r'^test.(?P<format>[a-z0-9]+)$', s11_render.TestView.as_view()),
url(r'test/(?P<pk>[/.]+)/$', s11_render.TestView.as_view()),
url(r'test/(?P<pk>[/.]+).(?P<format>[a-z0-9]+)$', s11_render.TestView.as_view())
]
from rest_framework.views import APIView from rest_framework.response import Response from .. import modelsclass TestView(APIView):
def get(self, request, *args, **kwargs):
print(kwargs)
print(self.renderer_classes)
return Response('...')
b. 半自动路由
from django.conf.urls import url, include from web.views import s10_genericurlpatterns = [
url(r'^test/$', s10_generic.UserViewSet.as_view({'get': 'list', 'post': 'create'})),
url(r'^test/(?P<pk>\d+)/$', s10_generic.UserViewSet.as_view(
{'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'})),
]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.viewsets import ModelViewSet from rest_framework import serializers from .. import modelsclass UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "all"class UserViewSet(ModelViewSet):
queryset = models.UserInfo.objects.all()
serializer_class = UserSerializer
c. 全自动路由
from django.conf.urls import url, include from rest_framework import routers from web.views import s10_genericrouter = routers.DefaultRouter()
router.register(r'users', s10_generic.UserViewSet)urlpatterns = [
url(r'^', include(router.urls)),
]
from rest_framework.viewsets import ModelViewSet from rest_framework import serializers from .. import modelsclass UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "all"class UserViewSet(ModelViewSet):
queryset = models.UserInfo.objects.all()
serializer_class = UserSerializer
9. 视图
a. GenericViewSet
from django.conf.urls import url, include from web.views.s7_viewset import TestViewurlpatterns = [
url(r'test/', TestView.as_view({'get':'list'}), name='test'),
url(r'detail/(?P<pk>\d+)/', TestView.as_view({'get':'list'}), name='xxxx'),
]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework import viewsets from rest_framework.response import Responseclass TestView(viewsets.GenericViewSet):
def list(self, request, *args, **kwargs):
return Response('...')</span><span style="color: #0000ff;">def</span> add(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">pass</span> <span style="color: #0000ff;">def</span> delete(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">pass</span> <span style="color: #0000ff;">def</span> edit(self, request, *args, **<span style="color: #000000;">kwargs): </span><span style="color: #0000ff;">pass</span></pre>
b. ModelViewSet(自定义URL)
from django.conf.urls import url, include from web.views import s10_genericurlpatterns = [
url(r'^test/$', s10_generic.UserViewSet.as_view({'get': 'list', 'post': 'create'})),
url(r'^test/(?P<pk>\d+)/$', s10_generic.UserViewSet.as_view(
{'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'})),
]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.viewsets import ModelViewSet from rest_framework import serializers from .. import modelsclass UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "all"class UserViewSet(ModelViewSet):
queryset = models.UserInfo.objects.all()
serializer_class = UserSerializer
c. ModelViewSet(rest framework路由)
from django.conf.urls import url, include from rest_framework import routers from app01 import viewsrouter = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'groups', views.GroupViewSet)# Wire up our API using automatic URL routing.
Additionally, we include login URLs for the browsable API.
urlpatterns = [
url(r'^', include(router.urls)),
]
from rest_framework import viewsets from rest_framework import serializersclass UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = models.User
fields = ('url', 'username', 'email', 'groups')class GroupSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = models.Group
fields = ('url', 'name')class UserViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = User.objects.all().order_by('-date_joined')
serializer_class = UserSerializerclass GroupViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows groups to be viewed or edited.
"""
queryset = Group.objects.all()
serializer_class = GroupSerializer
10. 渲染器
根据 用户请求URL 或 用户可接受的类型,筛选出合适的 渲染组件。
用户请求URL:
- http://127.0.0.1:8000/test/?format=json
- http://127.0.0.1:8000/test.json
用户请求头:
- Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
a. json
访问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/
from django.conf.urls import url, include from web.views import s11_renderurlpatterns = [
url(r'^test/$', s11_render.TestView.as_view()),
url(r'^test.(?P<format>[a-z0-9]+)', s11_render.TestView.as_view()),
]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializersfrom rest_framework.renderers import JSONRenderer
from .. import models
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "all"class TestView(APIView):
renderer_classes = [JSONRenderer, ]</span><span style="color: #0000ff;">def</span> get(self, request, *args, **<span style="color: #000000;">kwargs): user_list </span>=<span style="color: #000000;"> models.UserInfo.objects.all() ser </span>= TestSerializer(instance=user_list, many=<span style="color: #000000;">True) </span><span style="color: #0000ff;">return</span> Response(ser.data)</pre>
b. 表格
访问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/
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializersfrom rest_framework.renderers import AdminRenderer
from .. import models
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "all"class TestView(APIView):
renderer_classes = [AdminRenderer, ]</span><span style="color: #0000ff;">def</span> get(self, request, *args, **<span style="color: #000000;">kwargs): user_list </span>=<span style="color: #000000;"> models.UserInfo.objects.all() ser </span>= TestSerializer(instance=user_list, many=<span style="color: #000000;">True) </span><span style="color: #0000ff;">return</span> Response(ser.data)</pre>
c. Form表单
访问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/
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializersfrom rest_framework.renderers import JSONRenderer
from rest_framework.renderers import AdminRenderer
from rest_framework.renderers import HTMLFormRendererfrom .. import models
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "all"class TestView(APIView):
renderer_classes = [HTMLFormRenderer, ]</span><span style="color: #0000ff;">def</span> get(self, request, *args, **<span style="color: #000000;">kwargs): user_list </span>=<span style="color: #000000;"> models.UserInfo.objects.all().first() ser </span>= TestSerializer(instance=user_list, many=<span style="color: #000000;">False) </span><span style="color: #0000ff;">return</span> Response(ser.data)</pre>
d. 自定义显示模板
访问URL:
- http://127.0.0.1:8000/test/?format=html
- http://127.0.0.1:8000/test.html
- http://127.0.0.1:8000/test/
from django.conf.urls import url, include from web.views import s11_renderurlpatterns = [
url(r'^test/$', s11_render.TestView.as_view()),
url(r'^test.(?P<format>[a-z0-9]+)', s11_render.TestView.as_view()),
]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializers from rest_framework.renderers import TemplateHTMLRendererfrom .. import models
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "all"class TestView(APIView):
renderer_classes = [TemplateHTMLRenderer, ]</span><span style="color: #0000ff;">def</span> get(self, request, *args, **<span style="color: #000000;">kwargs): user_list </span>=<span style="color: #000000;"> models.UserInfo.objects.all().first() ser </span>= TestSerializer(instance=user_list, many=<span style="color: #000000;">False) </span><span style="color: #0000ff;">return</span> Response(ser.data, template_name=<span style="color: #800000;">'</span><span style="color: #800000;">user_detail.html</span><span style="color: #800000;">'</span>)</pre>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{ user }} {{ pwd }} {{ ut }} </body> </html>
e. 浏览器格式API+JSON
访问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/
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializersfrom rest_framework.renderers import JSONRenderer
from rest_framework.renderers import BrowsableAPIRendererfrom .. import models
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "all"class CustomBrowsableAPIRenderer(BrowsableAPIRenderer):
def get_default_renderer(self, view):
return JSONRenderer()class TestView(APIView):
renderer_classes = [CustomBrowsableAPIRenderer, ]</span><span style="color: #0000ff;">def</span> get(self, request, *args, **<span style="color: #000000;">kwargs): user_list </span>=<span style="color: #000000;"> models.UserInfo.objects.all().first() ser </span>= TestSerializer(instance=user_list, many=<span style="color: #000000;">False) </span><span style="color: #0000ff;">return</span> Response(ser.data, template_name=<span style="color: #800000;">'</span><span style="color: #800000;">user_detail.html</span><span style="color: #800000;">'</span>)</pre>
注意:如果同时多个存在时,自动根据URL后缀来选择渲染器。