一、什么是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 JsonResponse
class 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)
四、基于Django Rest Framework框架实现
4.1基本流程
url.py
from django.conf.urls import url, include
from web.views.s1_api import TestView
urlpatterns = [
url(r'^test/', TestView.as_view()),
]
views.py
from rest_framework.views import APIView
from rest_framework.response import Response
class TestView(APIView):
def 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请求,响应内容')
上述是rest framework框架基本流程,重要的功能是在APIView的dispatch中触发。
4.2认证和授权
1、用户url传入的token认证
url.py
from django.conf.urls import url, include
from web.viewsimport TestView
urlpatterns = [
url(r'^test/', TestView.as_view()),
]
1 from rest_framework.views import APIView 2 from rest_framework.response import Response 3 from rest_framework.authentication import BaseAuthentication 4 from rest_framework.request import Request 5 from rest_framework import exceptions 6 7 token_list = [ 8 'sfsfss123kuf3j123', 9 'asijnfowerkkf9812', 10 ] 11 12 13 class TestAuthentication(BaseAuthentication): 14 def authenticate(self, request): 15 """ 16 用户认证,如果验证成功后返回元组: (用户,用户Token) 17 :param request: 18 :return: 19 None,表示跳过该验证; 20 如果跳过了所有认证,默认用户和Token和使用配置文件进行设置 21 self._authenticator = None 22 if api_settings.UNAUTHENTICATED_USER: 23 self.user = api_settings.UNAUTHENTICATED_USER() 24 else: 25 self.user = None 26 27 if api_settings.UNAUTHENTICATED_TOKEN: 28 self.auth = api_settings.UNAUTHENTICATED_TOKEN() 29 else: 30 self.auth = None 31 (user,token)表示验证通过并设置用户名和Token; 32 AuthenticationFailed异常 33 """ 34 val = request.query_params.get('token') 35 if val not in token_list: 36 raise exceptions.AuthenticationFailed("用户认证失败") 37 38 return ('登录用户', '用户token') 39 40 def authenticate_header(self, request): 41 """ 42 Return a string to be used as the value of the `WWW-Authenticate` 43 header in a `401 Unauthenticated` response, or `None` if the 44 authentication scheme should return `403 Permission Denied` responses. 45 """ 46 # 验证失败时,返回的响应头WWW-Authenticate对应的值 47 pass 48 49 50 class TestView(APIView): 51 authentication_classes = [TestAuthentication, ] 52 permission_classes = [] 53 54 def get(self, request, *args, **kwargs): 55 print(request.user) 56 print(request.auth) 57 return Response('GET请求,响应内容') 58 59 def post(self, request, *args, **kwargs): 60 return Response('POST请求,响应内容') 61 62 def put(self, request, *args, **kwargs): 63 return Response('PUT请求,响应内容')
2、请求头认证
1 from django.conf.urls import url, include 2 from web.viewsimport TestView 3 4 urlpatterns = [ 5 url(r'^test/', TestView.as_view()), 6 ]
1 from rest_framework.views import APIView 2 from rest_framework.response import Response 3 from rest_framework.authentication import BaseAuthentication 4 from rest_framework.request import Request 5 from rest_framework import exceptions 6 7 token_list = [ 8 'sfsfss123kuf3j123', 9 'asijnfowerkkf9812', 10 ] 11 12 13 class TestAuthentication(BaseAuthentication): 14 def authenticate(self, request): 15 """ 16 用户认证,如果验证成功后返回元组: (用户,用户Token) 17 :param request: 18 :return: 19 None,表示跳过该验证; 20 如果跳过了所有认证,默认用户和Token和使用配置文件进行设置 21 self._authenticator = None 22 if api_settings.UNAUTHENTICATED_USER: 23 self.user = api_settings.UNAUTHENTICATED_USER() 24 else: 25 self.user = None 26 27 if api_settings.UNAUTHENTICATED_TOKEN: 28 self.auth = api_settings.UNAUTHENTICATED_TOKEN() 29 else: 30 self.auth = None 31 (user,token)表示验证通过并设置用户名和Token; 32 AuthenticationFailed异常 33 """ 34 import base64 35 auth = request.META.get('HTTP_AUTHORIZATION', b'') 36 if auth: 37 auth = auth.encode('utf-8') 38 auth = auth.split() 39 if not auth or auth[0].lower() != b'basic': 40 raise exceptions.AuthenticationFailed('验证失败') 41 if len(auth) != 2: 42 raise exceptions.AuthenticationFailed('验证失败') 43 username, part, password = base64.b64decode(auth[1]).decode('utf-8').partition(':') 44 if username == 'alex' and password == '123': 45 return ('登录用户', '用户token') 46 else: 47 raise exceptions.AuthenticationFailed('用户名或密码错误') 48 49 def authenticate_header(self, request): 50 """ 51 Return a string to be used as the value of the `WWW-Authenticate` 52 header in a `401 Unauthenticated` response, or `None` if the 53 authentication scheme should return `403 Permission Denied` responses. 54 """ 55 return 'Basic realm=api' 56 57 58 class TestView(APIView): 59 authentication_classes = [TestAuthentication, ] 60 permission_classes = [] 61 62 def get(self, request, *args, **kwargs): 63 print(request.user) 64 print(request.auth) 65 return Response('GET请求,响应内容') 66 67 def post(self, request, *args, **kwargs): 68 return Response('POST请求,响应内容') 69 70 def put(self, request, *args, **kwargs): 71 return Response('PUT请求,响应内容')
3、多个认证规则
1 from django.conf.urls import url, include 2 from web.views.s2_auth import TestView 3 4 urlpatterns = [ 5 url(r'^test/', TestView.as_view()), 6 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 from rest_framework.authentication import BaseAuthentication 6 from rest_framework.request import Request 7 from rest_framework import exceptions 8 9 token_list = [ 10 'sfsfss123kuf3j123', 11 'asijnfowerkkf9812', 12 ] 13 14 15 class Test1Authentication(BaseAuthentication): 16 def authenticate(self, request): 17 """ 18 用户认证,如果验证成功后返回元组: (用户,用户Token) 19 :param request: 20 :return: 21 None,表示跳过该验证; 22 如果跳过了所有认证,默认用户和Token和使用配置文件进行设置 23 self._authenticator = None 24 if api_settings.UNAUTHENTICATED_USER: 25 self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户 26 else: 27 self.user = None 28 29 if api_settings.UNAUTHENTICATED_TOKEN: 30 self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默认值为:None 31 else: 32 self.auth = None 33 (user,token)表示验证通过并设置用户名和Token; 34 AuthenticationFailed异常 35 """ 36 import base64 37 auth = request.META.get('HTTP_AUTHORIZATION', b'') 38 if auth: 39 auth = auth.encode('utf-8') 40 else: 41 return None 42 print(auth,'xxxx') 43 auth = auth.split() 44 if not auth or auth[0].lower() != b'basic': 45 raise exceptions.AuthenticationFailed('验证失败') 46 if len(auth) != 2: 47 raise exceptions.AuthenticationFailed('验证失败') 48 username, part, password = base64.b64decode(auth[1]).decode('utf-8').partition(':') 49 if username == 'alex' and password == '123': 50 return ('登录用户', '用户token') 51 else: 52 raise exceptions.AuthenticationFailed('用户名或密码错误') 53 54 def authenticate_header(self, request): 55 """ 56 Return a string to be used as the value of the `WWW-Authenticate` 57 header in a `401 Unauthenticated` response, or `None` if the 58 authentication scheme should return `403 Permission Denied` responses. 59 """ 60 # return 'Basic realm=api' 61 pass 62 63 class Test2Authentication(BaseAuthentication): 64 def authenticate(self, request): 65 """ 66 用户认证,如果验证成功后返回元组: (用户,用户Token) 67 :param request: 68 :return: 69 None,表示跳过该验证; 70 如果跳过了所有认证,默认用户和Token和使用配置文件进行设置 71 self._authenticator = None 72 if api_settings.UNAUTHENTICATED_USER: 73 self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户 74 else: 75 self.user = None 76 77 if api_settings.UNAUTHENTICATED_TOKEN: 78 self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默认值为:None 79 else: 80 self.auth = None 81 (user,token)表示验证通过并设置用户名和Token; 82 AuthenticationFailed异常 83 """ 84 val = request.query_params.get('token') 85 if val not in token_list: 86 raise exceptions.AuthenticationFailed("用户认证失败") 87 88 return ('登录用户', '用户token') 89 90 def authenticate_header(self, request): 91 """ 92 Return a string to be used as the value of the `WWW-Authenticate` 93 header in a `401 Unauthenticated` response, or `None` if the 94 authentication scheme should return `403 Permission Denied` responses. 95 """ 96 pass 97 98 99 class TestView(APIView): 100 authentication_classes = [Test1Authentication, Test2Authentication] 101 permission_classes = [] 102 103 def get(self, request, *args, **kwargs): 104 print(request.user) 105 print(request.auth) 106 return Response('GET请求,响应内容') 107 108 def post(self, request, *args, **kwargs): 109 return Response('POST请求,响应内容') 110 111 def put(self, request, *args, **kwargs): 112 return Response('PUT请求,响应内容')
4、认证和权限
1 from django.conf.urls import url, include 2 from web.views import TestView 3 4 urlpatterns = [ 5 url(r'^test/', TestView.as_view()), 6 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 from rest_framework.authentication import BaseAuthentication 6 from rest_framework.permissions import BasePermission 7 8 from rest_framework.request import Request 9 from rest_framework import exceptions 10 11 token_list = [ 12 'sfsfss123kuf3j123', 13 'asijnfowerkkf9812', 14 ] 15 16 17 class TestAuthentication(BaseAuthentication): 18 def authenticate(self, request): 19 """ 20 用户认证,如果验证成功后返回元组: (用户,用户Token) 21 :param request: 22 :return: 23 None,表示跳过该验证; 24 如果跳过了所有认证,默认用户和Token和使用配置文件进行设置 25 self._authenticator = None 26 if api_settings.UNAUTHENTICATED_USER: 27 self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户 28 else: 29 self.user = None 30 31 if api_settings.UNAUTHENTICATED_TOKEN: 32 self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默认值为:None 33 else: 34 self.auth = None 35 (user,token)表示验证通过并设置用户名和Token; 36 AuthenticationFailed异常 37 """ 38 val = request.query_params.get('token') 39 if val not in token_list: 40 raise exceptions.AuthenticationFailed("用户认证失败") 41 42 return ('登录用户', '用户token') 43 44 def authenticate_header(self, request): 45 """ 46 Return a string to be used as the value of the `WWW-Authenticate` 47 header in a `401 Unauthenticated` response, or `None` if the 48 authentication scheme should return `403 Permission Denied` responses. 49 """ 50 pass 51 52 53 class TestPermission(BasePermission): 54 message = "权限验证失败" 55 56 def has_permission(self, request, view): 57 """ 58 判断是否有权限访问当前请求 59 Return `True` if permission is granted, `False` otherwise. 60 :param request: 61 :param view: 62 :return: True有权限;False无权限 63 """ 64 if request.user == "管理员": 65 return True 66 67 # GenericAPIView中get_object时调用 68 def has_object_permission(self, request, view, obj): 69 """ 70 视图继承GenericAPIView,并在其中使用get_object时获取对象时,触发单独对象权限验证 71 Return `True` if permission is granted, `False` otherwise. 72 :param request: 73 :param view: 74 :param obj: 75 :return: True有权限;False无权限 76 """ 77 if request.user == "管理员": 78 return True 79 80 81 class TestView(APIView): 82 # 认证的动作是由request.user触发 83 authentication_classes = [TestAuthentication, ] 84 85 # 权限 86 # 循环执行所有的权限 87 permission_classes = [TestPermission, ] 88 89 def get(self, request, *args, **kwargs): 90 # self.dispatch 91 print(request.user) 92 print(request.auth) 93 return Response('GET请求,响应内容') 94 95 def post(self, request, *args, **kwargs): 96 return Response('POST请求,响应内容') 97 98 def put(self, request, *args, **kwargs): 99 return Response('PUT请求,响应内容')
5、全局使用
上述操作中均是对单独视图进行特殊配置,如果想要对全局进行配置,则需要再配置文件中写入即可。
1 REST_FRAMEWORK = { 2 'UNAUTHENTICATED_USER': None, 3 'UNAUTHENTICATED_TOKEN': None, 4 "DEFAULT_AUTHENTICATION_CLASSES": [ 5 "web.utils.TestAuthentication", 6 ], 7 "DEFAULT_PERMISSION_CLASSES": [ 8 "web.utils.TestPermission", 9 ], 10 }
1 from django.conf.urls import url, include 2 from web.views import TestView 3 4 urlpatterns = [ 5 url(r'^test/', TestView.as_view()), 6 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 6 class TestView(APIView): 7 8 def get(self, request, *args, **kwargs): 9 # self.dispatch 10 print(request.user) 11 print(request.auth) 12 return Response('GET请求,响应内容') 13 14 def post(self, request, *args, **kwargs): 15 return Response('POST请求,响应内容') 16 17 def put(self, request, *args, **kwargs): 18 return Response('PUT请求,响应内容')
4.3用户访问次数/频率限制
1、基于用户IP限制访问频率
1 from django.conf.urls import url, include 2 from web.views import TestView 3 4 urlpatterns = [ 5 url(r'^test/', TestView.as_view()), 6 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import time 4 from rest_framework.views import APIView 5 from rest_framework.response import Response 6 7 from rest_framework import exceptions 8 from rest_framework.throttling import BaseThrottle 9 from rest_framework.settings import api_settings 10 11 # 保存访问记录 12 RECORD = { 13 '用户IP': [12312139, 12312135, 12312133, ] 14 } 15 16 17 class TestThrottle(BaseThrottle): 18 ctime = time.time 19 20 def get_ident(self, request): 21 """ 22 根据用户IP和代理IP,当做请求者的唯一IP 23 Identify the machine making the request by parsing HTTP_X_FORWARDED_FOR 24 if present and number of proxies is > 0. If not use all of 25 HTTP_X_FORWARDED_FOR if it is available, if not use REMOTE_ADDR. 26 """ 27 xff = request.META.get('HTTP_X_FORWARDED_FOR') 28 remote_addr = request.META.get('REMOTE_ADDR') 29 num_proxies = api_settings.NUM_PROXIES 30 31 if num_proxies is not None: 32 if num_proxies == 0 or xff is None: 33 return remote_addr 34 addrs = xff.split(',') 35 client_addr = addrs[-min(num_proxies, len(addrs))] 36 return client_addr.strip() 37 38 return ''.join(xff.split()) if xff else remote_addr 39 40 def allow_request(self, request, view): 41 """ 42 是否仍然在允许范围内 43 Return `True` if the request should be allowed, `False` otherwise. 44 :param request: 45 :param view: 46 :return: True,表示可以通过;False表示已超过限制,不允许访问 47 """ 48 # 获取用户唯一标识(如:IP) 49 50 # 允许一分钟访问10次 51 num_request = 10 52 time_request = 60 53 54 now = self.ctime() 55 ident = self.get_ident(request) 56 self.ident = ident 57 if ident not in RECORD: 58 RECORD[ident] = [now, ] 59 return True 60 history = RECORD[ident] 61 while history and history[-1] <= now - time_request: 62 history.pop() 63 if len(history) < num_request: 64 history.insert(0, now) 65 return True 66 67 def wait(self): 68 """ 69 多少秒后可以允许继续访问 70 Optionally, return a recommended number of seconds to wait before 71 the next request. 72 """ 73 last_time = RECORD[self.ident][0] 74 now = self.ctime() 75 return int(60 + last_time - now) 76 77 78 class TestView(APIView): 79 throttle_classes = [TestThrottle, ] 80 81 def get(self, request, *args, **kwargs): 82 # self.dispatch 83 print(request.user) 84 print(request.auth) 85 return Response('GET请求,响应内容') 86 87 def post(self, request, *args, **kwargs): 88 return Response('POST请求,响应内容') 89 90 def put(self, request, *args, **kwargs): 91 return Response('PUT请求,响应内容') 92 93 def throttled(self, request, wait): 94 """ 95 访问次数被限制时,定制错误信息 96 """ 97 98 class Throttled(exceptions.Throttled): 99 default_detail = '请求被限制.' 100 extra_detail_singular = '请 {wait} 秒之后再重试.' 101 extra_detail_plural = '请 {wait} 秒之后再重试.' 102 103 raise Throttled(wait)
2、基于用户IP显示访问频率(利于Django缓存)
1 REST_FRAMEWORK = { 2 'DEFAULT_THROTTLE_RATES': { 3 'test_scope': '10/m', 4 }, 5 }
1 from django.conf.urls import url, include 2 from web.views import TestView 3 4 urlpatterns = [ 5 url(r'^test/', TestView.as_view()), 6 ]
3、view中限制请求频率
1 REST_FRAMEWORK = { 2 'DEFAULT_THROTTLE_RATES': { 3 'xxxxxx': '10/m', 4 }, 5 }
1 from django.conf.urls import url, include 2 from web.views import TestView 3 4 urlpatterns = [ 5 url(r'^test/', TestView.as_view()), 6 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 6 from rest_framework import exceptions 7 from rest_framework.throttling import ScopedRateThrottle 8 9 10 # 继承 ScopedRateThrottle 11 class TestThrottle(ScopedRateThrottle): 12 13 def get_cache_key(self, request, view): 14 """ 15 Should return a unique cache-key which can be used for throttling. 16 Must be overridden. 17 18 May return `None` if the request should not be throttled. 19 """ 20 if not request.user: 21 ident = self.get_ident(request) 22 else: 23 ident = request.user 24 25 return self.cache_format % { 26 'scope': self.scope, 27 'ident': ident 28 } 29 30 31 class TestView(APIView): 32 throttle_classes = [TestThrottle, ] 33 34 # 在settings中获取 xxxxxx 对应的频率限制值 35 throttle_scope = "xxxxxx" 36 37 def get(self, request, *args, **kwargs): 38 # self.dispatch 39 print(request.user) 40 print(request.auth) 41 return Response('GET请求,响应内容') 42 43 def post(self, request, *args, **kwargs): 44 return Response('POST请求,响应内容') 45 46 def put(self, request, *args, **kwargs): 47 return Response('PUT请求,响应内容') 48 49 def throttled(self, request, wait): 50 """ 51 访问次数被限制时,定制错误信息 52 """ 53 54 class Throttled(exceptions.Throttled): 55 default_detail = '请求被限制.' 56 extra_detail_singular = '请 {wait} 秒之后再重试.' 57 extra_detail_plural = '请 {wait} 秒之后再重试.' 58 59 raise Throttled(wait)
4、匿名时用IP限制+登录时用Token限制
1 REST_FRAMEWORK = { 2 'UNAUTHENTICATED_USER': None, 3 'UNAUTHENTICATED_TOKEN': None, 4 'DEFAULT_THROTTLE_RATES': { 5 'luffy_anon': '10/m', 6 'luffy_user': '20/m', 7 }, 8 }
1 from django.conf.urls import url, include 2 from web.views.s3_throttling import TestView 3 4 urlpatterns = [ 5 url(r'^test/', TestView.as_view()), 6 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 6 from rest_framework.throttling import SimpleRateThrottle 7 8 9 class LuffyAnonRateThrottle(SimpleRateThrottle): 10 """ 11 匿名用户,根据IP进行限制 12 """ 13 scope = "luffy_anon" 14 15 def get_cache_key(self, request, view): 16 # 用户已登录,则跳过 匿名频率限制 17 if request.user: 18 return None 19 20 return self.cache_format % { 21 'scope': self.scope, 22 'ident': self.get_ident(request) 23 } 24 25 26 class LuffyUserRateThrottle(SimpleRateThrottle): 27 """ 28 登录用户,根据用户token限制 29 """ 30 scope = "luffy_user" 31 32 def get_ident(self, request): 33 """ 34 认证成功时:request.user是用户对象;request.auth是token对象 35 :param request: 36 :return: 37 """ 38 # return request.auth.token 39 return "user_token" 40 41 def get_cache_key(self, request, view): 42 """ 43 获取缓存key 44 :param request: 45 :param view: 46 :return: 47 """ 48 # 未登录用户,则跳过 Token限制 49 if not request.user: 50 return None 51 52 return self.cache_format % { 53 'scope': self.scope, 54 'ident': self.get_ident(request) 55 } 56 57 58 class TestView(APIView): 59 throttle_classes = [LuffyUserRateThrottle, LuffyAnonRateThrottle, ] 60 61 def get(self, request, *args, **kwargs): 62 # self.dispatch 63 print(request.user) 64 print(request.auth) 65 return Response('GET请求,响应内容') 66 67 def post(self, request, *args, **kwargs): 68 return Response('POST请求,响应内容') 69 70 def put(self, request, *args, **kwargs): 71 return Response('PUT请求,响应内容')
5、全局使用
1 REST_FRAMEWORK = { 2 'DEFAULT_THROTTLE_CLASSES': [ 3 'api.utils.throttles.throttles.LuffyAnonRateThrottle', 4 'api.utils.throttles.throttles.LuffyUserRateThrottle', 5 ], 6 'DEFAULT_THROTTLE_RATES': { 7 'anon': '10/day', 8 'user': '10/day', 9 'luffy_anon': '10/m', 10 'luffy_user': '20/m', 11 }, 12 }
4.4版本
1、基于url的get传参方式
如:/users?version=v1
1 REST_FRAMEWORK = { 2 'DEFAULT_VERSION': 'v1', # 默认版本 3 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本 4 'VERSION_PARAM': 'version' # URL中获取值的key 5 }
1 from django.conf.urls import url, include 2 from web.views import TestView 3 4 urlpatterns = [ 5 url(r'^test/', TestView.as_view(),name='test'), 6 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 from rest_framework.versioning import QueryParameterVersioning 6 7 8 class TestView(APIView): 9 versioning_class = QueryParameterVersioning 10 11 def get(self, request, *args, **kwargs): 12 13 # 获取版本 14 print(request.version) 15 # 获取版本管理的类 16 print(request.versioning_scheme) 17 18 # 反向生成URL 19 reverse_url = request.versioning_scheme.reverse('test', request=request) 20 print(reverse_url) 21 22 return Response('GET请求,响应内容') 23 24 def post(self, request, *args, **kwargs): 25 return Response('POST请求,响应内容') 26 27 def put(self, request, *args, **kwargs): 28 return Response('PUT请求,响应内容')
2、基于url的正则方式
如:/v1/users/
1 REST_FRAMEWORK = { 2 'DEFAULT_VERSION': 'v1', # 默认版本 3 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本 4 'VERSION_PARAM': 'version' # URL中获取值的key 5 }
1 from django.conf.urls import url, include 2 from web.views import TestView 3 4 urlpatterns = [ 5 url(r'^(?P<version>[v1|v2]+)/test/', TestView.as_view(), name='test'), 6 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 from rest_framework.versioning import URLPathVersioning 6 7 8 class TestView(APIView): 9 versioning_class = URLPathVersioning 10 11 def get(self, request, *args, **kwargs): 12 # 获取版本 13 print(request.version) 14 # 获取版本管理的类 15 print(request.versioning_scheme) 16 17 # 反向生成URL 18 reverse_url = request.versioning_scheme.reverse('test', request=request) 19 print(reverse_url) 20 21 return Response('GET请求,响应内容') 22 23 def post(self, request, *args, **kwargs): 24 return Response('POST请求,响应内容') 25 26 def put(self, request, *args, **kwargs): 27 return Response('PUT请求,响应内容')
3、基于 accept 请求头方式
如:Accept: application/json; version=1.0
1 REST_FRAMEWORK = { 2 'DEFAULT_VERSION': 'v1', # 默认版本 3 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本 4 'VERSION_PARAM': 'version' # URL中获取值的key 5 }
1 from django.conf.urls import url, include 2 from web.views import TestView 3 4 urlpatterns = [ 5 url(r'^test/', TestView.as_view(), name='test'), 6 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 from rest_framework.versioning import AcceptHeaderVersioning 6 7 8 class TestView(APIView): 9 versioning_class = AcceptHeaderVersioning 10 11 def get(self, request, *args, **kwargs): 12 # 获取版本 HTTP_ACCEPT头 13 print(request.version) 14 # 获取版本管理的类 15 print(request.versioning_scheme) 16 # 反向生成URL 17 reverse_url = request.versioning_scheme.reverse('test', request=request) 18 print(reverse_url) 19 20 return Response('GET请求,响应内容') 21 22 def post(self, request, *args, **kwargs): 23 return Response('POST请求,响应内容') 24 25 def put(self, request, *args, **kwargs): 26 return Response('PUT请求,响应内容')
4、基于主机名方法
如:v1.example.com
1 ALLOWED_HOSTS = ['*'] 2 REST_FRAMEWORK = { 3 'DEFAULT_VERSION': 'v1', # 默认版本 4 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本 5 'VERSION_PARAM': 'version' # URL中获取值的key 6 }
1 from django.conf.urls import url, include 2 from web.views import TestView 3 4 urlpatterns = [ 5 url(r'^test/', TestView.as_view(), name='test'), 6 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 from rest_framework.versioning import HostNameVersioning 6 7 8 class TestView(APIView): 9 versioning_class = HostNameVersioning 10 11 def get(self, request, *args, **kwargs): 12 # 获取版本 13 print(request.version) 14 # 获取版本管理的类 15 print(request.versioning_scheme) 16 # 反向生成URL 17 reverse_url = request.versioning_scheme.reverse('test', request=request) 18 print(reverse_url) 19 20 return Response('GET请求,响应内容') 21 22 def post(self, request, *args, **kwargs): 23 return Response('POST请求,响应内容') 24 25 def put(self, request, *args, **kwargs): 26 return Response('PUT请求,响应内容')
5、基于django路由系统的namespace
如:example.com/v1/users/
1 REST_FRAMEWORK = { 2 'DEFAULT_VERSION': 'v1', # 默认版本 3 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本 4 'VERSION_PARAM': 'version' # URL中获取值的key 5 }
1 from django.conf.urls import url, include 2 from web.views import TestView 3 4 urlpatterns = [ 5 url(r'^v1/', ([ 6 url(r'test/', TestView.as_view(), name='test'), 7 ], None, 'v1')), 8 url(r'^v2/', ([ 9 url(r'test/', TestView.as_view(), name='test'), 10 ], None, 'v2')), 11 12 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 from rest_framework.versioning import NamespaceVersioning 6 7 8 class TestView(APIView): 9 versioning_class = NamespaceVersioning 10 11 def get(self, request, *args, **kwargs): 12 # 获取版本 13 print(request.version) 14 # 获取版本管理的类 15 print(request.versioning_scheme) 16 # 反向生成URL 17 reverse_url = request.versioning_scheme.reverse('test', request=request) 18 print(reverse_url) 19 20 return Response('GET请求,响应内容') 21 22 def post(self, request, *args, **kwargs): 23 return Response('POST请求,响应内容') 24 25 def put(self, request, *args, **kwargs): 26 return Response('PUT请求,响应内容')
6、全局使用
1 REST_FRAMEWORK = { 2 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning", 3 'DEFAULT_VERSION': 'v1', 4 'ALLOWED_VERSIONS': ['v1', 'v2'], 5 'VERSION_PARAM': 'version' 6 }
4.5解释器(parser)
根据请求头 content-type 选择对应的解析器就请求体内容进行处理。
1、仅处理请求头content-type为application/json的请求体
1 from django.conf.urls import url, include 2 from web.views.s5_parser import TestView 3 4 urlpatterns = [ 5 url(r'test/', TestView.as_view(), name='test'), 6 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 from rest_framework.request import Request 6 from rest_framework.parsers import JSONParser 7 8 9 class TestView(APIView): 10 parser_classes = [JSONParser, ] 11 12 def post(self, request, *args, **kwargs): 13 print(request.content_type) 14 15 # 获取请求的值,并使用对应的JSONParser进行处理 16 print(request.data) 17 18 # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值 19 print(request.POST) 20 print(request.FILES) 21 22 return Response('POST请求,响应内容') 23 24 def put(self, request, *args, **kwargs): 25 return Response('PUT请求,响应内容')
2、仅处理请求头content-type为application/x-www-form-urlencoded 的请求体
1 from django.conf.urls import url, include 2 from web.views import TestView 3 4 urlpatterns = [ 5 url(r'test/', TestView.as_view(), name='test'), 6 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 from rest_framework.request import Request 6 from rest_framework.parsers import FormParser 7 8 9 class TestView(APIView): 10 parser_classes = [FormParser, ] 11 12 def post(self, request, *args, **kwargs): 13 print(request.content_type) 14 15 # 获取请求的值,并使用对应的JSONParser进行处理 16 print(request.data) 17 18 # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值 19 print(request.POST) 20 print(request.FILES) 21 22 return Response('POST请求,响应内容') 23 24 def put(self, request, *args, **kwargs): 25 return Response('PUT请求,响应内容')
3、仅处理请求头content-type为multipart/form-data的请求体
1 from django.conf.urls import url, include 2 from web.views import TestView 3 4 urlpatterns = [ 5 url(r'test/', TestView.as_view(), name='test'), 6 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 from rest_framework.request import Request 6 from rest_framework.parsers import MultiPartParser 7 8 9 class TestView(APIView): 10 parser_classes = [MultiPartParser, ] 11 12 def post(self, request, *args, **kwargs): 13 print(request.content_type) 14 15 # 获取请求的值,并使用对应的JSONParser进行处理 16 print(request.data) 17 # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值 18 print(request.POST) 19 print(request.FILES) 20 return Response('POST请求,响应内容') 21 22 def put(self, request, *args, **kwargs): 23 return Response('PUT请求,响应内容')
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 <form action="http://127.0.0.1:8000/test/" method="post" enctype="multipart/form-data"> 9 <input type="text" name="user" /> 10 <input type="file" name="img"> 11 12 <input type="submit" value="提交"> 13 14 </form> 15 </body> 16 </html>
4、仅上传文件
1 from django.conf.urls import url, include 2 from web.views import TestView 3 4 urlpatterns = [ 5 url(r'test/(?P<filename>[^/]+)', TestView.as_view(), name='test'), 6 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 from rest_framework.request import Request 6 from rest_framework.parsers import FileUploadParser 7 8 9 class TestView(APIView): 10 parser_classes = [FileUploadParser, ] 11 12 def post(self, request, filename, *args, **kwargs): 13 print(filename) 14 print(request.content_type) 15 16 # 获取请求的值,并使用对应的JSONParser进行处理 17 print(request.data) 18 # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值 19 print(request.POST) 20 print(request.FILES) 21 return Response('POST请求,响应内容') 22 23 def put(self, request, *args, **kwargs): 24 return Response('PUT请求,响应内容')
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 <form action="http://127.0.0.1:8000/test/f1.numbers" method="post" enctype="multipart/form-data"> 9 <input type="text" name="user" /> 10 <input type="file" name="img"> 11 12 <input type="submit" value="提交"> 13 14 </form> 15 </body> 16 </html> 17 复制代码
5、同时多个Parser
当同时使用多个parser时,rest framework会根据请求头content-type自动进行比对,并使用对应parser
1 from django.conf.urls import url, include 2 from web.views import TestView 3 4 urlpatterns = [ 5 url(r'test/', TestView.as_view(), name='test'), 6 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 from rest_framework.request import Request 6 from rest_framework.parsers import JSONParser, FormParser, MultiPartParser 7 8 9 class TestView(APIView): 10 parser_classes = [JSONParser, FormParser, MultiPartParser, ] 11 12 def post(self, request, *args, **kwargs): 13 print(request.content_type) 14 15 # 获取请求的值,并使用对应的JSONParser进行处理 16 print(request.data) 17 # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值 18 print(request.POST) 19 print(request.FILES) 20 return Response('POST请求,响应内容') 21 22 def put(self, request, *args, **kwargs): 23 return Response('PUT请求,响应内容')
6、全局使用
1 REST_FRAMEWORK = { 2 'DEFAULT_PARSER_CLASSES':[ 3 'rest_framework.parsers.JSONParser' 4 'rest_framework.parsers.FormParser' 5 'rest_framework.parsers.MultiPartParser' 6 ] 7 8 }
1 from django.conf.urls import url, include 2 from web.views import TestView 3 4 urlpatterns = [ 5 url(r'test/', TestView.as_view(), name='test'), 6 ]
1 from rest_framework.views import APIView 2 from rest_framework.response import Response 3 4 5 class TestView(APIView): 6 def post(self, request, *args, **kwargs): 7 print(request.content_type) 8 9 # 获取请求的值,并使用对应的JSONParser进行处理 10 print(request.data) 11 # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值 12 print(request.POST) 13 print(request.FILES) 14 return Response('POST请求,响应内容') 15 16 def put(self, request, *args, **kwargs): 17 return Response('PUT请求,响应内容')
注意:个别特殊的值可以通过Django的request对象 request._request 来进行获取
4.6序列化
序列化用于对用户请求数据进行验证和数据进行序列化。
1、自定义字段
1 from django.conf.urls import url, include 2 from web.views.s6_serializers import TestView 3 4 urlpatterns = [ 5 url(r'test/', TestView.as_view(), name='test'), 6 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 from rest_framework import serializers 6 from .. import models 7 8 9 class PasswordValidator(object): 10 def __init__(self, base): 11 self.base = base 12 13 def __call__(self, value): 14 if value != self.base: 15 message = 'This field must be %s.' % self.base 16 raise serializers.ValidationError(message) 17 18 def set_context(self, serializer_field): 19 """ 20 This hook is called by the serializer instance, 21 prior to the validation call being made. 22 """ 23 # 执行验证之前调用,serializer_fields是当前字段对象 24 pass 25 26 27 class UserSerializer(serializers.Serializer): 28 ut_title = serializers.CharField(source='ut.title') 29 user = serializers.CharField(min_length=6) 30 pwd = serializers.CharField(error_messages={'required': '密码不能为空'}, validators=[PasswordValidator('666')]) 31 32 33 class TestView(APIView): 34 def get(self, request, *args, **kwargs): 35 36 # 序列化,将数据库查询字段序列化为字典 37 data_list = models.UserInfo.objects.all() 38 ser = UserSerializer(instance=data_list, many=True) 39 # 或 40 # obj = models.UserInfo.objects.all().first() 41 # ser = UserSerializer(instance=obj, many=False) 42 return Response(ser.data) 43 44 def post(self, request, *args, **kwargs): 45 # 验证,对请求发来的数据进行验证 46 ser = UserSerializer(data=request.data) 47 if ser.is_valid(): 48 print(ser.validated_data) 49 else: 50 print(ser.errors) 51 52 return Response('POST请求,响应内容')
2、基于Model自动生成字段
1 from django.conf.urls import url, include 2 from web.views.s6_serializers import TestView 3 4 urlpatterns = [ 5 url(r'test/', TestView.as_view(), name='test'), 6 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 from rest_framework import serializers 6 from .. import models 7 8 9 class PasswordValidator(object): 10 def __init__(self, base): 11 self.base = str(base) 12 13 def __call__(self, value): 14 if value != self.base: 15 message = 'This field must be %s.' % self.base 16 raise serializers.ValidationError(message) 17 18 def set_context(self, serializer_field): 19 """ 20 This hook is called by the serializer instance, 21 prior to the validation call being made. 22 """ 23 # 执行验证之前调用,serializer_fields是当前字段对象 24 pass 25 26 class ModelUserSerializer(serializers.ModelSerializer): 27 28 user = serializers.CharField(max_length=32) 29 30 class Meta: 31 model = models.UserInfo 32 fields = "__all__" 33 # fields = ['user', 'pwd', 'ut'] 34 depth = 2 35 extra_kwargs = {'user': {'min_length': 6}, 'pwd': {'validators': [PasswordValidator(666), ]}} 36 # read_only_fields = ['user'] 37 38 39 class TestView(APIView): 40 def get(self, request, *args, **kwargs): 41 42 # 序列化,将数据库查询字段序列化为字典 43 data_list = models.UserInfo.objects.all() 44 ser = ModelUserSerializer(instance=data_list, many=True) 45 # 或 46 # obj = models.UserInfo.objects.all().first() 47 # ser = UserSerializer(instance=obj, many=False) 48 return Response(ser.data) 49 50 def post(self, request, *args, **kwargs): 51 # 验证,对请求发来的数据进行验证 52 print(request.data) 53 ser = ModelUserSerializer(data=request.data) 54 if ser.is_valid(): 55 print(ser.validated_data) 56 else: 57 print(ser.errors) 58 59 return Response('POST请求,响应内容')
3、生成URL
1 from django.conf.urls import url, include 2 from web.views.s6_serializers import TestView 3 4 urlpatterns = [ 5 url(r'test/', TestView.as_view(), name='test'), 6 url(r'detail/(?P<pk>\d+)/', TestView.as_view(), name='detail'), 7 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 from rest_framework import serializers 6 from .. import models 7 8 9 class PasswordValidator(object): 10 def __init__(self, base): 11 self.base = str(base) 12 13 def __call__(self, value): 14 if value != self.base: 15 message = 'This field must be %s.' % self.base 16 raise serializers.ValidationError(message) 17 18 def set_context(self, serializer_field): 19 """ 20 This hook is called by the serializer instance, 21 prior to the validation call being made. 22 """ 23 # 执行验证之前调用,serializer_fields是当前字段对象 24 pass 25 26 27 class ModelUserSerializer(serializers.ModelSerializer): 28 ut = serializers.HyperlinkedIdentityField(view_name='detail') 29 class Meta: 30 model = models.UserInfo 31 fields = "__all__" 32 33 extra_kwargs = { 34 'user': {'min_length': 6}, 35 'pwd': {'validators': [PasswordValidator(666),]}, 36 } 37 38 39 40 class TestView(APIView): 41 def get(self, request, *args, **kwargs): 42 43 # 序列化,将数据库查询字段序列化为字典 44 data_list = models.UserInfo.objects.all() 45 ser = ModelUserSerializer(instance=data_list, many=True, context={'request': request}) 46 # 或 47 # obj = models.UserInfo.objects.all().first() 48 # ser = UserSerializer(instance=obj, many=False) 49 return Response(ser.data) 50 51 def post(self, request, *args, **kwargs): 52 # 验证,对请求发来的数据进行验证 53 print(request.data) 54 ser = ModelUserSerializer(data=request.data) 55 if ser.is_valid(): 56 print(ser.validated_data) 57 else: 58 print(ser.errors) 59 60 return Response('POST请求,响应内容')
4、自动生成URL
1 from django.conf.urls import url, include 2 from web.views.s6_serializers import TestView 3 4 urlpatterns = [ 5 url(r'test/', TestView.as_view(), name='test'), 6 url(r'detail/(?P<pk>\d+)/', TestView.as_view(), name='xxxx'), 7 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 from rest_framework import serializers 6 from .. import models 7 8 9 class PasswordValidator(object): 10 def __init__(self, base): 11 self.base = str(base) 12 13 def __call__(self, value): 14 if value != self.base: 15 message = 'This field must be %s.' % self.base 16 raise serializers.ValidationError(message) 17 18 def set_context(self, serializer_field): 19 """ 20 This hook is called by the serializer instance, 21 prior to the validation call being made. 22 """ 23 # 执行验证之前调用,serializer_fields是当前字段对象 24 pass 25 26 27 class ModelUserSerializer(serializers.HyperlinkedModelSerializer): 28 ll = serializers.HyperlinkedIdentityField(view_name='xxxx') 29 tt = serializers.CharField(required=False) 30 31 class Meta: 32 model = models.UserInfo 33 fields = "__all__" 34 list_serializer_class = serializers.ListSerializer 35 36 extra_kwargs = { 37 'user': {'min_length': 6}, 38 'pwd': {'validators': [PasswordValidator(666), ]}, 39 'url': {'view_name': 'xxxx'}, 40 'ut': {'view_name': 'xxxx'}, 41 } 42 43 44 class TestView(APIView): 45 def get(self, request, *args, **kwargs): 46 # # 序列化,将数据库查询字段序列化为字典 47 data_list = models.UserInfo.objects.all() 48 ser = ModelUserSerializer(instance=data_list, many=True, context={'request': request}) 49 # # 如果Many=True 50 # # 或 51 # # obj = models.UserInfo.objects.all().first() 52 # # ser = UserSerializer(instance=obj, many=False) 53 return Response(ser.data) 54 55 def post(self, request, *args, **kwargs): 56 # 验证,对请求发来的数据进行验证 57 print(request.data) 58 ser = ModelUserSerializer(data=request.data) 59 if ser.is_valid(): 60 print(ser.validated_data) 61 else: 62 print(ser.errors) 63 64 return Response('POST请求,响应内容')
4.7分页
1、根据页码进行分页
1 from django.conf.urls import url, include 2 from rest_framework import routers 3 from web.views import s9_pagination 4 5 urlpatterns = [ 6 url(r'^test/', s9_pagination.UserViewSet.as_view()), 7 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework import serializers 5 from .. import models 6 7 from rest_framework.pagination import PageNumberPagination 8 9 10 class StandardResultsSetPagination(PageNumberPagination): 11 # 默认每页显示的数据条数 12 page_size = 1 13 # 获取URL参数中设置的每页显示数据条数 14 page_size_query_param = 'page_size' 15 16 # 获取URL参数中传入的页码key 17 page_query_param = 'page' 18 19 # 最大支持的每页显示的数据条数 20 max_page_size = 1 21 22 23 class UserSerializer(serializers.ModelSerializer): 24 class Meta: 25 model = models.UserInfo 26 fields = "__all__" 27 28 29 class UserViewSet(APIView): 30 def get(self, request, *args, **kwargs): 31 user_list = models.UserInfo.objects.all().order_by('-id') 32 33 # 实例化分页对象,获取数据库中的分页数据 34 paginator = StandardResultsSetPagination() 35 page_user_list = paginator.paginate_queryset(user_list, self.request, view=self) 36 37 # 序列化对象 38 serializer = UserSerializer(page_user_list, many=True) 39 40 # 生成分页和数据 41 response = paginator.get_paginated_response(serializer.data) 42 return response
2、位置和个数进行分页
1 from django.conf.urls import url, include 2 from web.views import s9_pagination 3 4 urlpatterns = [ 5 url(r'^test/', s9_pagination.UserViewSet.as_view()), 6 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework import serializers 5 from .. import models 6 7 from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination 8 9 10 class StandardResultsSetPagination(LimitOffsetPagination): 11 # 默认每页显示的数据条数 12 default_limit = 10 13 # URL中传入的显示数据条数的参数 14 limit_query_param = 'limit' 15 # URL中传入的数据位置的参数 16 offset_query_param = 'offset' 17 # 最大每页显得条数 18 max_limit = None 19 20 class UserSerializer(serializers.ModelSerializer): 21 class Meta: 22 model = models.UserInfo 23 fields = "__all__" 24 25 26 class UserViewSet(APIView): 27 def get(self, request, *args, **kwargs): 28 user_list = models.UserInfo.objects.all().order_by('-id') 29 30 # 实例化分页对象,获取数据库中的分页数据 31 paginator = StandardResultsSetPagination() 32 page_user_list = paginator.paginate_queryset(user_list, self.request, view=self) 33 34 # 序列化对象 35 serializer = UserSerializer(page_user_list, many=True) 36 37 # 生成分页和数据 38 response = paginator.get_paginated_response(serializer.data) 39 return response
3、游标分页
1 from django.conf.urls import url, include 2 from web.views import s9_pagination 3 4 urlpatterns = [ 5 url(r'^test/', s9_pagination.UserViewSet.as_view()), 6 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework import serializers 5 from .. import models 6 7 from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination 8 9 10 class StandardResultsSetPagination(CursorPagination): 11 # URL传入的游标参数 12 cursor_query_param = 'cursor' 13 # 默认每页显示的数据条数 14 page_size = 2 15 # URL传入的每页显示条数的参数 16 page_size_query_param = 'page_size' 17 # 每页显示数据最大条数 18 max_page_size = 1000 19 20 # 根据ID从大到小排列 21 ordering = "id" 22 23 24 25 class UserSerializer(serializers.ModelSerializer): 26 class Meta: 27 model = models.UserInfo 28 fields = "__all__" 29 30 31 class UserViewSet(APIView): 32 def get(self, request, *args, **kwargs): 33 user_list = models.UserInfo.objects.all().order_by('-id') 34 35 # 实例化分页对象,获取数据库中的分页数据 36 paginator = StandardResultsSetPagination() 37 page_user_list = paginator.paginate_queryset(user_list, self.request, view=self) 38 39 # 序列化对象 40 serializer = UserSerializer(page_user_list, many=True) 41 42 # 生成分页和数据 43 response = paginator.get_paginated_response(serializer.data) 44 return response
4.8路由系统
1、自定义路由
1 from django.conf.urls import url, include 2 from web.views import s11_render 3 4 urlpatterns = [ 5 url(r'^test/$', s11_render.TestView.as_view()), 6 url(r'^test\.(?P<format>[a-z0-9]+)$', s11_render.TestView.as_view()), 7 url(r'^test/(?P<pk>[^/.]+)/$', s11_render.TestView.as_view()), 8 url(r'^test/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)$', s11_render.TestView.as_view()) 9 ]
1 from rest_framework.views import APIView 2 from rest_framework.response import Response 3 from .. import models 4 5 6 class TestView(APIView): 7 def get(self, request, *args, **kwargs): 8 print(kwargs) 9 print(self.renderer_classes) 10 return Response('...')
2、半自动路由
1 from django.conf.urls import url, include 2 from web.views import s10_generic 3 4 urlpatterns = [ 5 url(r'^test/$', s10_generic.UserViewSet.as_view({'get': 'list', 'post': 'create'})), 6 url(r'^test/(?P<pk>\d+)/$', s10_generic.UserViewSet.as_view( 7 {'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'})), 8 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.viewsets import ModelViewSet 4 from rest_framework import serializers 5 from .. import models 6 7 8 class UserSerializer(serializers.ModelSerializer): 9 class Meta: 10 model = models.UserInfo 11 fields = "__all__" 12 13 14 class UserViewSet(ModelViewSet): 15 queryset = models.UserInfo.objects.all() 16 serializer_class = UserSerializer
3、全自动路由
1 from django.conf.urls import url, include 2 from rest_framework import routers 3 from web.views import s10_generic 4 5 6 router = routers.DefaultRouter() 7 router.register(r'users', s10_generic.UserViewSet) 8 9 urlpatterns = [ 10 url(r'^', include(router.urls)), 11 ]
1 from rest_framework.viewsets import ModelViewSet 2 from rest_framework import serializers 3 from .. import models 4 5 6 class UserSerializer(serializers.ModelSerializer): 7 class Meta: 8 model = models.UserInfo 9 fields = "__all__" 10 11 12 class UserViewSet(ModelViewSet): 13 queryset = models.UserInfo.objects.all() 14 serializer_class = UserSerializer
4.9视图
1、GenericViewSet
1 from django.conf.urls import url, include 2 from web.views.s7_viewset import TestView 3 4 urlpatterns = [ 5 url(r'test/', TestView.as_view({'get':'list'}), name='test'), 6 url(r'detail/(?P<pk>\d+)/', TestView.as_view({'get':'list'}), name='xxxx'), 7 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework import viewsets 4 from rest_framework.response import Response 5 6 7 class TestView(viewsets.GenericViewSet): 8 def list(self, request, *args, **kwargs): 9 return Response('...') 10 11 def add(self, request, *args, **kwargs): 12 pass 13 14 def delete(self, request, *args, **kwargs): 15 pass 16 17 def edit(self, request, *args, **kwargs): 18 pass
2、ModelViewSet(自定义URL)
1 from django.conf.urls import url, include 2 from web.views import s10_generic 3 4 urlpatterns = [ 5 url(r'^test/$', s10_generic.UserViewSet.as_view({'get': 'list', 'post': 'create'})), 6 url(r'^test/(?P<pk>\d+)/$', s10_generic.UserViewSet.as_view( 7 {'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'})), 8 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.viewsets import ModelViewSet 4 from rest_framework import serializers 5 from .. import models 6 7 8 class UserSerializer(serializers.ModelSerializer): 9 class Meta: 10 model = models.UserInfo 11 fields = "__all__" 12 13 14 class UserViewSet(ModelViewSet): 15 queryset = models.UserInfo.objects.all() 16 serializer_class = UserSerializer
3、ModelViewSet(rest framework路由)
1 from django.conf.urls import url, include 2 from rest_framework import routers 3 from app01 import views 4 5 router = routers.DefaultRouter() 6 router.register(r'users', views.UserViewSet) 7 router.register(r'groups', views.GroupViewSet) 8 9 # Wire up our API using automatic URL routing. 10 # Additionally, we include login URLs for the browsable API. 11 urlpatterns = [ 12 url(r'^', include(router.urls)), 13 ]
1 from rest_framework import viewsets 2 from rest_framework import serializers 3 4 5 class UserSerializer(serializers.HyperlinkedModelSerializer): 6 class Meta: 7 model = models.User 8 fields = ('url', 'username', 'email', 'groups') 9 10 11 class GroupSerializer(serializers.HyperlinkedModelSerializer): 12 class Meta: 13 model = models.Group 14 fields = ('url', 'name') 15 16 class UserViewSet(viewsets.ModelViewSet): 17 """ 18 API endpoint that allows users to be viewed or edited. 19 """ 20 queryset = User.objects.all().order_by('-date_joined') 21 serializer_class = UserSerializer 22 23 24 class GroupViewSet(viewsets.ModelViewSet): 25 """ 26 API endpoint that allows groups to be viewed or edited. 27 """ 28 queryset = Group.objects.all() 29 serializer_class = GroupSerializer
4.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
1、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/
1 from django.conf.urls import url, include 2 from web.views import s11_render 3 4 urlpatterns = [ 5 url(r'^test/$', s11_render.TestView.as_view()), 6 url(r'^test\.(?P<format>[a-z0-9]+)', s11_render.TestView.as_view()), 7 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 from rest_framework import serializers 6 7 from rest_framework.renderers import JSONRenderer 8 9 from .. import models 10 11 12 class TestSerializer(serializers.ModelSerializer): 13 class Meta: 14 model = models.UserInfo 15 fields = "__all__" 16 17 18 class TestView(APIView): 19 renderer_classes = [JSONRenderer, ] 20 21 def get(self, request, *args, **kwargs): 22 user_list = models.UserInfo.objects.all() 23 ser = TestSerializer(instance=user_list, many=True) 24 return Response(ser.data)
2、 表格
访问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/
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 from rest_framework import serializers 6 7 from rest_framework.renderers import AdminRenderer 8 9 from .. import models 10 11 12 class TestSerializer(serializers.ModelSerializer): 13 class Meta: 14 model = models.UserInfo 15 fields = "__all__" 16 17 18 class TestView(APIView): 19 renderer_classes = [AdminRenderer, ] 20 21 def get(self, request, *args, **kwargs): 22 user_list = models.UserInfo.objects.all() 23 ser = TestSerializer(instance=user_list, many=True) 24 return Response(ser.data)
3、 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/
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 from rest_framework import serializers 6 7 from rest_framework.renderers import JSONRenderer 8 from rest_framework.renderers import AdminRenderer 9 from rest_framework.renderers import HTMLFormRenderer 10 11 from .. import models 12 13 14 class TestSerializer(serializers.ModelSerializer): 15 class Meta: 16 model = models.UserInfo 17 fields = "__all__" 18 19 20 class TestView(APIView): 21 renderer_classes = [HTMLFormRenderer, ] 22 23 def get(self, request, *args, **kwargs): 24 user_list = models.UserInfo.objects.all().first() 25 ser = TestSerializer(instance=user_list, many=False) 26 return Response(ser.data)
4、自定义显示模板
访问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/
1 from django.conf.urls import url, include 2 from web.views import s11_render 3 4 urlpatterns = [ 5 url(r'^test/$', s11_render.TestView.as_view()), 6 url(r'^test\.(?P<format>[a-z0-9]+)', s11_render.TestView.as_view()), 7 ]
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 from rest_framework import serializers 6 from rest_framework.renderers import TemplateHTMLRenderer 7 8 from .. import models 9 10 11 class TestSerializer(serializers.ModelSerializer): 12 class Meta: 13 model = models.UserInfo 14 fields = "__all__" 15 16 17 class TestView(APIView): 18 renderer_classes = [TemplateHTMLRenderer, ] 19 20 def get(self, request, *args, **kwargs): 21 user_list = models.UserInfo.objects.all().first() 22 ser = TestSerializer(instance=user_list, many=False) 23 return Response(ser.data, template_name='user_detail.html')
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 {{ user }} 9 {{ pwd }} 10 {{ ut }} 11 </body> 12 </html>
5、 浏览器格式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/
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 from rest_framework.views import APIView 4 from rest_framework.response import Response 5 from rest_framework import serializers 6 7 from rest_framework.renderers import JSONRenderer 8 from rest_framework.renderers import BrowsableAPIRenderer 9 10 from .. import models 11 12 13 class TestSerializer(serializers.ModelSerializer): 14 class Meta: 15 model = models.UserInfo 16 fields = "__all__" 17 18 19 class CustomBrowsableAPIRenderer(BrowsableAPIRenderer): 20 def get_default_renderer(self, view): 21 return JSONRenderer() 22 23 24 class TestView(APIView): 25 renderer_classes = [CustomBrowsableAPIRenderer, ] 26 27 def get(self, request, *args, **kwargs): 28 user_list = models.UserInfo.objects.all().first() 29 ser = TestSerializer(instance=user_list, many=False) 30 return Response(ser.data, template_name='user_detail.html')
注意:如果同时多个存在时,自动根据URL后缀来选择渲染器。