一. 什么是RESTful html
一、REST与技术无关,表明的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”python
二、REST从资源的角度类审视整个网络,它将分布在网络中某个节点的资源经过URL进行标识,客户端应用经过URL来获取资源的表征,得到这些表征导致这些应用转变状态web
三、全部的数据,不过是经过网络获取的仍是操做(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其余架构风格的最本质属性数据库
四、对于REST这种面向资源的架构风格,有人提出一种全新的结构理念,即:面向资源架构(ROA:Resource Oriented Architecture)django
二. RESTful API设计json
一、API与用户的通讯协议,老是使用HTTPs协议。api
二、域名跨域
https://api.example.com 尽可能将API部署在专用域名(会存在跨域问题)数组
https://example.org/api/ API很简单浏览器
三、版本
URL,如:https://api.example.com/v1/ 请求头跨域时,引起发送屡次请求
四、路径,视网络上任何东西都是资源,均使用名词表示(可复数即后面加s)
https://api.example.com/v1/zoos
https://api.example.com/v1/animals
https://api.example.com/v1/employees
五、method
GET :从服务器取出资源(一项或多项)
POST :在服务器新建一个资源
PUT :在服务器更新资源(客户端提供改变后的完整资源,所有更新用put)
PATCH :在服务器更新资源(客户端提供改变的属性,局部更新用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 - [*]:服务器发生错误,用户将没法判断发出的请求是否成功。
八、错误处理,状态码是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" }}
三. 基于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框架实现
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中触发
二、版本
a. 基于url的get传参方式。如:/users?version=v1
全局配置:在settings中配置 REST_FRAMEWORK = { 'DEFAULT_VERSION': 'v1', # 默认版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 容许的版本
'VERSION_PARAM': 'version' # URL中获取值的key
"DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.QueryParameterVersioning", #指定默认版本传参路径
} 局部配置:在view中配置 局部配置就须要在每一个view视图中添加上versioning_class=QueryParameterVersionin
from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r'^test/', TestView.as_view(),name='test'), ]
#!/usr/bin/env python # -*- coding:utf-8 -*-
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.versioning import QueryParameterVersioning class TestView(APIView): //versioning_class = QueryParameterVersioning def get(self, request, *args, **kwargs): # 获取版本
print(request.version) # 获取版本管理的类
print(request.versioning_scheme) # 反向生成URL
reverse_url = request.versioning_scheme.reverse('test', request=request) print(reverse_url) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')
b. 基于url的正则方式如:/v1/users/
REST_FRAMEWORK = { 'DEFAULT_VERSION': 'v1', # 默认版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 容许的版本
'VERSION_PARAM': 'version' # URL中获取值的key
"DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning", }
from django.conf.urls import url, include from web.views import TestView urlpatterns = [ 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 URLPathVersioning class TestView(APIView): versioning_class = URLPathVersioning def get(self, request, *args, **kwargs): # 获取版本
print(request.version) # 获取版本管理的类
print(request.versioning_scheme) # 反向生成URL
reverse_url = request.versioning_scheme.reverse('test', request=request) print(reverse_url) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')
c. 基于 accept 请求头方式如:Accept: application/json; version=1.0
REST_FRAMEWORK = { 'DEFAULT_VERSION': 'v1', # 默认版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 容许的版本
'VERSION_PARAM': 'version' # URL中获取值的key
"DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.AcceptHeaderVersioning", }
from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r'^test/', TestView.as_view(), name='test'), ]
#!/usr/bin/env python # -*- coding:utf-8 -*-
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.versioning import AcceptHeaderVersioning class TestView(APIView): versioning_class = AcceptHeaderVersioning def get(self, request, *args, **kwargs): # 获取版本 HTTP_ACCEPT头
print(request.version) # 获取版本管理的类
print(request.versioning_scheme) # 反向生成URL
reverse_url = request.versioning_scheme.reverse('test', request=request) print(reverse_url) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')
d. 基于主机名方法如:v1.example.com
ALLOWED_HOSTS = ['*'] REST_FRAMEWORK = { 'DEFAULT_VERSION': 'v1', # 默认版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 容许的版本
'VERSION_PARAM': 'version' # URL中获取值的key
"DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.HostNameVersioning", }
from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r'^test/', TestView.as_view(), name='test'), ]
#!/usr/bin/env python # -*- coding:utf-8 -*-
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.versioning import HostNameVersioning class TestView(APIView): versioning_class = HostNameVersioning def get(self, request, *args, **kwargs): # 获取版本
print(request.version) # 获取版本管理的类
print(request.versioning_scheme) # 反向生成URL
reverse_url = request.versioning_scheme.reverse('test', request=request) print(reverse_url) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')
e. 基于django路由系统的namespace如:example.com/v1/users/
REST_FRAMEWORK = { 'DEFAULT_VERSION': 'v1', # 默认版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 容许的版本
'VERSION_PARAM': 'version' # URL中获取值的key
"DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.NamespaceVersioning", }
from django.conf.urls import url, include from web.views import TestView urlpatterns = [ 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 NamespaceVersioning class TestView(APIView): versioning_class = NamespaceVersioning def get(self, request, *args, **kwargs): # 获取版本
print(request.version) # 获取版本管理的类
print(request.versioning_scheme) # 反向生成URL
reverse_url = request.versioning_scheme.reverse('test', request=request) print(reverse_url) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')
f.总结:
一、若是想要看到'rest_framework'特制的错误页面就须要把'rest_framework'给注册到settings中的INSTALLED_APPS中 2、rest_framework生命周期: 1. 中间件 2. 路由系统 3. 视图 - request二次封装(解析器,认证,选择,view+参数) - try: - 获取版本 - 认证 - 权限 - 节流 - response = GET/POST/DELETE等方法 - except: - response = 异常 - 处理响应内容 3、版本控制: 视图类中配置: from rest_framework.versioning import URLPathVersioning class UsersView(APIView): versioning_class = URLPathVersioning 配置文件中: 注册APP: 'rest_framework', REST_FRAMEWORK = { "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning", "VERSION_PARAM":"version", "DEFAULT_VERSION":'v1', "ALLOWED_VERSIONS":['v1','v2'] } 获取和反向生成URL print(request.version) print(request.versioning_scheme.reverse(viewname='xxxx',request=request))
三、认证
a. 用户url传入的token认证
from django.conf.urls import url, include from web.viewsimport TestView urlpatterns = [ 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 exceptions token_list = [ 'sfsfss123kuf3j123', 'asijnfowerkkf9812', ] class TestAuthentication(BaseAuthentication)://本身写一个认证的类,而且必须继承BaseAuthentication类,并且要继承和从新BaseAuthentication这个类下的方法 def authenticate(self, request): """ 用户认证,若是验证成功后返回元组: (用户,用户Token) 若是返回None,表示跳过该验证; 若是跳过了全部认证,默认用户和Token和使用配置文件进行设置 """ val = request.query_params.get('token') //query_params封装了原生的request的GET请求,等同于_request.GET if val not in token_list: raise exceptions.AuthenticationFailed("用户认证失败") return ('登陆用户', '用户token') def authenticate_header(self, request): # 验证失败时,返回的响应头WWW-Authenticate对应的值,通常不用
pass
class TestView(APIView): authentication_classes = [TestAuthentication, ]//局部应用 def get(self, request, *args, **kwargs): print(request.user) print(request.auth) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容') 注释:用户必须先认证经过TestAuthentication类,即能成功登录才能访问TestView类下的方法
b、请求头认证
from django.conf.urls import url, include from web.viewsimport TestView urlpatterns = [ 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 exceptions token_list = [ 'sfsfss123kuf3j123', 'asijnfowerkkf9812', ] class TestAuthentication(BaseAuthentication): def authenticate(self, request): #用户认证,若是验证成功后返回元组: (用户,用户Token)None,表示跳过该验证;若是跳过了全部认证,默认用户和Token和使用配置文件进行设置
import base64 auth = request.META.get('HTTP_AUTHORIZATION', b'') #META封装了_request.POST
if auth: auth = auth.encode('utf-8') auth = auth.split() if not auth or auth[0].lower() != b'basic': raise exceptions.AuthenticationFailed('验证失败') if len(auth) != 2: raise exceptions.AuthenticationFailed('验证失败') username, part, password = base64.b64decode(auth[1]).decode('utf-8').partition(':') if username == 'alex' and password == '123': return ('登陆用户', '用户token') else: raise exceptions.AuthenticationFailed('用户名或密码错误') def authenticate_header(self, request): return 'Basic realm=api'
class TestView(APIView): authentication_classes = [TestAuthentication, ] def get(self, request, *args, **kwargs): print(request.user) print(request.auth) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')
c、多个认证规则
from django.conf.urls import url, include from web.views.s2_auth import TestView urlpatterns = [ 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 exceptions token_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 = None if api_settings.UNAUTHENTICATED_TOKEN: self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默认值为:None else: self.auth = None (user,token)表示验证经过并设置用户名和Token; AuthenticationFailed异常 """
import base64 auth = request.META.get('HTTP_AUTHORIZATION', b'') if auth: auth = auth.encode('utf-8') else: return None print(auth,'xxxx') auth = auth.split() if not auth or auth[0].lower() != b'basic': raise exceptions.AuthenticationFailed('验证失败') if len(auth) != 2: raise exceptions.AuthenticationFailed('验证失败') username, part, password = base64.b64decode(auth[1]).decode('utf-8').partition(':') if username == 'alex' and password == '123': return ('登陆用户', '用户token') else: raise exceptions.AuthenticationFailed('用户名或密码错误') def authenticate_header(self, request): """ 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. """
# return 'Basic realm=api'
pass
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 = None if api_settings.UNAUTHENTICATED_TOKEN: self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默认值为:None else: self.auth = None (user,token)表示验证经过并设置用户名和Token; AuthenticationFailed异常 """ val = request.query_params.get('token') if val not in token_list: raise exceptions.AuthenticationFailed("用户认证失败") return ('登陆用户', '用户token') def authenticate_header(self, request): """ 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. """
pass
class TestView(APIView): authentication_classes = [Test1Authentication, Test2Authentication] permission_classes = [] def get(self, request, *args, **kwargs): print(request.user) print(request.auth) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容') 复制代码
四、权限
a、
from django.conf.urls import url, include from web.views import TestView urlpatterns = [ 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.permissions import BasePermission from rest_framework.request import Request from rest_framework import exceptions token_list = [ 'sfsfss123kuf3j123', 'asijnfowerkkf9812', ] class TestAuthentication(BaseAuthentication): def authenticate(self, request): val = request.query_params.get('token') if val not in token_list: raise exceptions.AuthenticationFailed("用户认证失败") return ('登陆用户', '用户token') def authenticate_header(self, request): pass
class TestPermission(BasePermission): message = "权限验证失败"
def has_permission(self, request, view): """ 判断是否有权限访问当前请求,return: True有权限;False无权限 """
if request.user == "管理员": return True # GenericAPIView中get_object时调用
def has_object_permission(self, request, view, obj): """ 视图继承GenericAPIView,并在其中使用get_object时获取对象时,触发单独对象权限验证,return: True有权限;False无权限 """
if request.user == "管理员": return True class TestView(APIView): # 认证的动做是由request.user触发
authentication_classes = [TestAuthentication, ] # 权限
# 循环执行全部的权限
permission_classes = [TestPermission, ] def get(self, request, *args, **kwargs): # self.dispatch
print(request.user) print(request.auth) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')
b、全局设置
REST_FRAMEWORK = { 'UNAUTHENTICATED_USER': None, 'UNAUTHENTICATED_TOKEN': None, "DEFAULT_AUTHENTICATION_CLASSES": [ "web.utils.TestAuthentication", ], "DEFAULT_PERMISSION_CLASSES": [ "web.utils.TestPermission", ], }
五、限制用户访问次数
a、基于用户IP限制访问频率
from django.conf.urls import url, include from web.views import TestView urlpatterns = [ 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 Response from 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 def get_ident(self, request): """ 根据用户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. """ xff = request.META.get('HTTP_X_FORWARDED_FOR') remote_addr = request.META.get('REMOTE_ADDR') num_proxies = api_settings.NUM_PROXIES if num_proxies is not None: if num_proxies == 0 or xff is None: return remote_addr addrs = xff.split(',') client_addr = addrs[-min(num_proxies, len(addrs))] return client_addr.strip() return ''.join(xff.split()) if xff else remote_addr def allow_request(self, request, view): """ 是否仍然在容许范围内 Return `True` if the request should be allowed, `False` otherwise. :param request: :param view: :return: True,表示能够经过;False表示已超过限制,不容许访问 """
# 获取用户惟一标识(如:IP)
# 容许一分钟访问10次
num_request = 10 time_request = 60 now = self.ctime() ident = self.get_ident(request) self.ident = ident if ident not in RECORD: RECORD[ident] = [now, ] return True history = RECORD[ident] while history and history[-1] <= now - time_request: history.pop() if len(history) < num_request: history.insert(0, now) return True def wait(self): """ 多少秒后能够容许继续访问 Optionally, return a recommended number of seconds to wait before the next request. """ last_time = RECORD[self.ident][0] now = self.ctime() return int(60 + last_time - now) class TestView(APIView): throttle_classes = [TestThrottle, ] def get(self, request, *args, **kwargs): # self.dispatch
print(request.user) print(request.auth) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容') def throttled(self, request, wait): """ 访问次数被限制时,定制错误信息 """
class Throttled(exceptions.Throttled): default_detail = '请求被限制.' extra_detail_singular = '请 {wait} 秒以后再重试.' extra_detail_plural = '请 {wait} 秒以后再重试.'
raise Throttled(wait)
b、基于用户IP显示访问频率(利于Django缓存)
REST_FRAMEWORK = { 'DEFAULT_THROTTLE_RATES': { 'test_scope': '10/m', }, }
from django.conf.urls import url, include from web.views import TestView urlpatterns = [ 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 import exceptions from rest_framework.throttling import SimpleRateThrottle class TestThrottle(SimpleRateThrottle): # 配置文件定义的显示频率的Key
scope = "test_scope"
def get_cache_key(self, request, view): """ 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. """
if not request.user: ident = self.get_ident(request) else: ident = request.user return self.cache_format % { 'scope': self.scope, 'ident': ident } class TestView(APIView): throttle_classes = [TestThrottle, ] def get(self, request, *args, **kwargs): # self.dispatch
print(request.user) print(request.auth) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容') def throttled(self, request, wait): """ 访问次数被限制时,定制错误信息 """
class Throttled(exceptions.Throttled): default_detail = '请求被限制.' extra_detail_singular = '请 {wait} 秒以后再重试.' extra_detail_plural = '请 {wait} 秒以后再重试.'
raise Throttled(wait)
c、view中限制请求频率
REST_FRAMEWORK = { 'DEFAULT_THROTTLE_RATES': { 'xxxxxx': '10/m', }, }
from django.conf.urls import url, include from web.views import TestView urlpatterns = [ 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 import exceptions from rest_framework.throttling import ScopedRateThrottle # 继承 ScopedRateThrottle
class TestThrottle(ScopedRateThrottle): def get_cache_key(self, request, view): """ 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. """
if not request.user: ident = self.get_ident(request) else: ident = request.user return self.cache_format % { 'scope': self.scope, 'ident': ident } class TestView(APIView): throttle_classes = [TestThrottle, ] # 在settings中获取 xxxxxx 对应的频率限制值
throttle_scope = "xxxxxx"
def get(self, request, *args, **kwargs): # self.dispatch
print(request.user) print(request.auth) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容') def throttled(self, request, wait): """ 访问次数被限制时,定制错误信息 """
class Throttled(exceptions.Throttled): default_detail = '请求被限制.' extra_detail_singular = '请 {wait} 秒以后再重试.' extra_detail_plural = '请 {wait} 秒以后再重试.'
raise Throttled(wait)
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 TestView urlpatterns = [ 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.throttling import SimpleRateThrottle class LuffyAnonRateThrottle(SimpleRateThrottle): """ 匿名用户,根据IP进行限制 """ scope = "luffy_anon"
def get_cache_key(self, request, view): # 用户已登陆,则跳过 匿名频率限制
if request.user: return None return self.cache_format % { 'scope': self.scope, 'ident': self.get_ident(request) } class LuffyUserRateThrottle(SimpleRateThrottle): """ 登陆用户,根据用户token限制 """ scope = "luffy_user"
def get_ident(self, request): """ 认证成功时:request.user是用户对象;request.auth是token对象 :param request: :return: """
# return request.auth.token
return "user_token"
def get_cache_key(self, request, view): """ 获取缓存key :param request: :param view: :return: """
# 未登陆用户,则跳过 Token限制
if not request.user: return None return self.cache_format % { 'scope': self.scope, 'ident': self.get_ident(request) } class TestView(APIView): throttle_classes = [LuffyUserRateThrottle, LuffyAnonRateThrottle, ] def get(self, request, *args, **kwargs): # self.dispatch
print(request.user) print(request.auth) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')
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', }, }
六、解析器(parser)
a、仅处理请求头content-type为application/json的请求体
from django.conf.urls import url, include from web.views.s5_parser import TestView urlpatterns = [ url(r'test/', TestView.as_view(), name='test'), ]
#!/usr/bin/env python # -*- coding:utf-8 -*-
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.request import Request from rest_framework.parsers import JSONParser class TestView(APIView): parser_classes = [JSONParser, ] def post(self, request, *args, **kwargs): print(request.content_type) # 获取请求的值,并使用对应的JSONParser进行处理
print(request.data) # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
print(request.POST) print(request.FILES) return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')
b、仅处理请求头content-type为application/x-www-form-urlencoded 的请求体
from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r'test/', TestView.as_view(), name='test'), ]
#!/usr/bin/env python # -*- coding:utf-8 -*-
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.request import Request from rest_framework.parsers import FormParser class TestView(APIView): parser_classes = [FormParser, ] def post(self, request, *args, **kwargs): print(request.content_type) # 获取请求的值,并使用对应的JSONParser进行处理
print(request.data) # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
print(request.POST) print(request.FILES) return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')
c、仅处理请求头content-type为multipart/form-data的请求体
from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r'test/', TestView.as_view(), name='test'), ]
#!/usr/bin/env python # -*- coding:utf-8 -*-
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.request import Request from rest_framework.parsers import MultiPartParser class TestView(APIView): parser_classes = [MultiPartParser, ] def post(self, request, *args, **kwargs): print(request.content_type) # 获取请求的值,并使用对应的JSONParser进行处理
print(request.data) # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
print(request.POST) print(request.FILES) return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://127.0.0.1:8000/test/" method="post" enctype="multipart/form-data">
<input type="text" name="user" />
<input type="file" name="img">
<input type="submit" value="提交">
</form>
</body>
</html>
d. 仅上传文件
from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r'test/(?P<filename>[^/]+)', TestView.as_view(), name='test'), ]
#!/usr/bin/env python # -*- coding:utf-8 -*-
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.request import Request from rest_framework.parsers import FileUploadParser class TestView(APIView): parser_classes = [FileUploadParser, ] def post(self, request, filename, *args, **kwargs): print(filename) print(request.content_type) # 获取请求的值,并使用对应的JSONParser进行处理
print(request.data) # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
print(request.POST) print(request.FILES) return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://127.0.0.1:8000/test/f1.numbers" method="post" enctype="multipart/form-data">
<input type="text" name="user" />
<input type="file" name="img">
<input type="submit" value="提交">
</form>
</body>
</html>
e. 同时多个Parser(当同时使用多个parser时,rest framework会根据请求头content-type自动进行比对,并使用对应parser)
from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r'test/', TestView.as_view(), name='test'), ]
#!/usr/bin/env python # -*- coding:utf-8 -*-
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.request import Request from rest_framework.parsers import JSONParser, FormParser, MultiPartParser class TestView(APIView): parser_classes = [JSONParser, FormParser, MultiPartParser, ] def post(self, request, *args, **kwargs): print(request.content_type) # 获取请求的值,并使用对应的JSONParser进行处理
print(request.data) # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
print(request.POST) print(request.FILES) return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')
f. 全局使用
REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES':[ 'rest_framework.parsers.JSONParser'
'rest_framework.parsers.FormParser'
'rest_framework.parsers.MultiPartParser' ] }
七、序列化(序列化用于对用户请求数据进行验证和数据进行序列化)
a. 自定义字段
from django.conf.urls import url, include from web.views.s6_serializers import TestView urlpatterns = [ url(r'test/', TestView.as_view(), name='test'), ]
#!/usr/bin/env python # -*- coding:utf-8 -*-
from rest_framework.views import APIView from .. import models class PasswordValidator(object): def __init__(self, base): self.base = base def __call__(self, value): if value != self.base: #value是用户发送过来的值
message = 'This field must be %s.' % self.base raise serializers.ValidationError(message) def set_context(self, serializer_field): # 执行验证以前调用,serializer_fields是当前字段对象
pass
from rest_framework.response import Response from rest_framework import serializers class UserSerializer(serializers.Serializer): email=serializers.EmailFied() ut_title = serializers.CharField(source='ut.title',required=False) #跨表拿组相关信息,source='ut.title'表示拿组的title信息,ut确定是该表外键字段,requiredb=False表示能够不填
user = serializers.CharField(min_length=6) #表示拿user字段相关信息,而且验证字段最小长度为6
pwd = serializers.CharField(error_messages={'required': '密码不能为空'}, validators=[PasswordValidator('666')])#required表示自定制错误信息,validators表示自定制验证规则,请求发过来的数据要
#验证就须要执行__call__方法,而后你就能够在__call__方法内写本身的验证规则
class TestView(APIView): def get(self, request, *args, **kwargs): # instance:序列化,将数据库查询字段序列化为字典而后发送 给用户
data_list = models.UserInfo.objects.all() ser = UserSerializer(instance=data_list, many=True) #因为ser是个列表,因此many=True
# 或
# obj = models.UserInfo.objects.all().first()
# ser = UserSerializer(instance=obj, many=False) #因为ser是个对象,因此many=False
return Response(ser.data) #ser.data就把数据库中的数据所有都转换成有序字典,而且用rest_framework为咱们封装好的Response返回序列化后的结果
def post(self, request, *args, **kwargs): #data: 验证,对请求发来的数据进行验证
ser = UserSerializer(data=request.data) if ser.is_valid(): #验证用户发送过来的数据是否符合表字段的规范,若是都符合就打印正确字段信息,只要有一个不符合就只打印不符合字段信息
print(ser.validated_data) else: print(ser.errors) return Response('POST请求,响应内容')
b. 基于Model自动生成字段
from django.conf.urls import url, include from web.views.s6_serializers import TestView urlpatterns = [ url(r'test/', TestView.as_view(), name='test'), ]
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializers from .. import models class PasswordValidator(object): def __init__(self, base): self.base = str(base) def __call__(self, value): if value != self.base: message = 'This field must be %s.' % self.base raise serializers.ValidationError(message) def set_context(self, serializer_field): # 执行验证以前调用,serializer_fields是当前字段对象
pass
class ModelUserSerializer(serializers.ModelSerializer): user = serializers.CharField(max_length=32)#额外的写另一个字段,若是新写的字段和表中某个字段相同则至关于重写表字段
class Meta: model = models.UserInfo fields = "__all__" #能够取表中所有字段,也能够自定制取哪些字段
# fields = ['user', 'pwd', 'ut']
depth = 2 #深度查询,意思就是说当一个表中有外键时,能够查询外键字段对应的表字段全部信息
extra_kwargs = {'user': {'min_length': 6}, 'pwd': {'validators': [PasswordValidator(666), ]}} # read_only_fields = ['user']
class TestView(APIView): def get(self, request, *args, **kwargs): # 序列化,将数据库查询字段序列化为字典
data_list = models.UserInfo.objects.all() ser = ModelUserSerializer(instance=data_list, many=True) # 拿表中的多个或单个值,而后序列化成字符串返回给用户
# obj = models.UserInfo.objects.all().first()
# ser = UserSerializer(instance=obj, many=False)
return Response(ser.data) def post(self, request, *args, **kwargs): # 验证,对请求发来的数据进行验证
print(request.data) ser = ModelUserSerializer(data=request.data) if ser.is_valid(): print(ser.validated_data) else: print(ser.errors) return Response('POST请求,响应内容')
c. 手动生成URL
from django.conf.urls import url, include from web.views.s6_serializers import TestView urlpatterns = [ url(r'test/', TestView.as_view(), name='test'), url(r'detail/(?P<pk>\d+)/', TestView.as_view(), name='detail'), ]
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializers from .. import models class PasswordValidator(object): def __init__(self, base): self.base = str(base) def __call__(self, value): if value != self.base: message = 'This field must be %s.' % self.base raise serializers.ValidationError(message) def set_context(self, serializer_field): # 执行验证以前调用,serializer_fields是当前字段对象
pass
class ModelUserSerializer(serializers.ModelSerializer): ut = serializers.HyperlinkedIdentityField(view_name='detail') #view_name指的是在路由系统的url中反向生成url的名称,ut指代的是反向生成的url,可是必须在Serializer实例化的时候添加上context={'request': request}才能够
class Meta: model = models.UserInfo fields = "__all__" extra_kwargs = { #自定义验证规则
'user': {'min_length': 6}, 'pwd': {'validators': [PasswordValidator(666),]}, } depth=2 #会自动查找深度为2的外键对象关系表中全部字段数据,而后把数据一并返回给客户端
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})#实例化产生一个对象,对象.data获得字符串,再Response就是字符串序列化
# 或
# obj = models.UserInfo.objects.all().first()
# ser = UserSerializer(instance=obj, many=False)
return Response(ser.data) def post(self, request, *args, **kwargs): # 验证,对请求发来的数据进行验证
print(request.data) ser = ModelUserSerializer(data=request.data) if ser.is_valid(): print(ser.validated_data) else: print(ser.errors) return Response('POST请求,响应内容')
d. 自动生成URL
from django.conf.urls import url, include from web.views.s6_serializers import TestView urlpatterns = [ url(r'test/', TestView.as_view(), name='test'), url(r'detail/(?P<pk>\d+)/', TestView.as_view(), name='表名-detail'), ] #pk是本身字段id,这个name内必须写 '代表-detail'
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializers from .. import models class PasswordValidator(object): def __init__(self, base): self.base = str(base) def __call__(self, value): if value != self.base: message = 'This field must be %s.' % self.base raise serializers.ValidationError(message) def set_context(self, serializer_field): # 执行验证以前调用,serializer_fields是当前字段对象
pass
class ModelUserSerializer(serializers.HyperlinkedModelSerializer): #ll = serializers.HyperlinkedIdentityField(view_name='表名-detail') #能够不用写这两个,由于他说自动帮咱们生成url
#tt = serializers.CharField(required=False)
class Meta: model = models.UserInfo fields = "__all__"#若是报错则能够写chengfields=[user,pwd,url],其中url是程序自动生成的
list_serializer_class = serializers.ListSerializer extra_kwargs = { 'user': {'min_length': 6}, 'pwd': {'validators': [PasswordValidator(666), ]}, 'url': {'view_name': 'xxxx'}, 'ut': {'view_name': 'xxxx'}, } 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) def post(self, request, *args, **kwargs): # 验证,对请求发来的数据进行验证
print(request.data) ser = ModelUserSerializer(data=request.data) if ser.is_valid(): print(ser.validated_data) else: print(ser.errors) return Response('POST请求,响应内容')
八、分页
a、根据页码进行分页
from django.conf.urls import url, include from rest_framework import routers from web.views import s9_pagination urlpatterns = [ url(r'^test/', s9_pagination.UserViewSet.as_view()), ]
from rest_framework.views import APIView from rest_framework import serializers from .. import models from rest_framework.pagination import PageNumberPagination class StandardResultsSetPagination(PageNumberPagination): # 默认每页显示的数据条数
page_size = 1
# 获取URL参数中设置的每页显示数据条数
page_size_query_param = 'page_size'
# 获取URL参数中传入的页码key
page_query_param = 'page' #127.0.0.1/pages?page=1,即获取1这个数据
# 最大支持的每页显示的数据条数
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') # 实例化分页对象,获取数据库中的分页数据
paginator = StandardResultsSetPagination() page_user_list = paginator.paginate_queryset(user_list, self.request, view=self) # 序列化对象
serializer = UserSerializer(page_user_list, many=True) # 生成分页和数据
response = paginator.get_paginated_response(serializer.data) #不只返回json后的数据还会生成上一页的连接和下一页的连接
return response
b、位置和个数进行分页
from django.conf.urls import url, include from web.views import s9_pagination urlpatterns = [ url(r'^test/', s9_pagination.UserViewSet.as_view()), ]
from rest_framework.views import APIView from rest_framework import serializers from .. import models from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination class StandardResultsSetPagination(LimitOffsetPagination): # 默认每页显示的数据条数
default_limit = 10
# URL中传入的显示数据条数的参数
limit_query_param = 'limit'
# URL中传入的数据位置的参数
offset_query_param = 'offset'
# 最大每页显得条数
max_limit = None 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') # 实例化分页对象,获取数据库中的分页数据
paginator = StandardResultsSetPagination() page_user_list = paginator.paginate_queryset(user_list, self.request, view=self) # 序列化对象
serializer = UserSerializer(page_user_list, many=True) # 生成分页和数据
response = paginator.get_paginated_response(serializer.data) return response
c. 游标分页
from django.conf.urls import url, include from web.views import s9_pagination urlpatterns = [ url(r'^test/', s9_pagination.UserViewSet.as_view()), ]
from rest_framework.views import APIView from rest_framework import serializers from .. import models from 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
# 根据ID从大到小排列
ordering = "id"
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') # 实例化分页对象,获取数据库中的分页数据
paginator = StandardResultsSetPagination() page_user_list = paginator.paginate_queryset(user_list, self.request, view=self) # 序列化对象
serializer = UserSerializer(page_user_list, many=True) # 生成分页和数据
response = paginator.get_paginated_response(serializer.data) return response
九、路由系统
a、自定义路由
from django.conf.urls import url, include from web.views import s11_render urlpatterns = [ url(r'^test/$', s11_render.TestView.as_view()), #普通url
url(r'^test\.(?P<format>\w+)$', s11_render.TestView.as_view()), #后面跟后缀的url,(test.json,test.admin等)
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 models class TestView(APIView): def get(self, request, *args, **kwargs): print(kwargs) #打印的是个字典,和{‘format’:‘...’}
print(self.renderer_classes) return Response('...')
b. 半自动路
from django.conf.urls import url, include from web.views import s10_generic urlpatterns = [ url(r'^test/$', s10_generic.UserViewSet.as_view({'get': 'list', 'post': 'create'})),#get请求对应的是list,查的是整个表数据,retrieve查的是个对象,post请求对应的是create,update请求对应的是update,delete请求对应的是destroy,
url(r'^test/(?P<pk>\d+)/$', s10_generic.UserViewSet.as_view( {'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'})), ]
from rest_framework.viewsets import ModelViewSet from rest_framework import serializers from .. import models class 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_generic #先导入view中的继承了ModelViewSet的那个类
router = routers.DefaultRouter() router.register('index', s10_generic) #index指代的是url的前缀,经过127.0.0.1/index/访问全部数据,127.0.0.1/index/1/访问id为1的数据 # 注释:只要router.register('index', s10_generic) 就会为这个s10_generic类生成对应的四个url
#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())
urlpatterns = [ url(r'^', include(router.urls)), ]
from rest_framework.viewsets import ModelViewSet from rest_framework import serializers from .. import models class UserSerializer(serializers.ModelSerializer): class Meta: model = models.UserInfo fields = "__all__"
class UserViewSet(ModelViewSet): queryset = models.UserInfo.objects.all() serializer_class = UserSerializer 复制代码
10. 视图
a. GenericViewSet
from django.conf.urls import url, include from web.views.s7_viewset import TestView urlpatterns = [ url(r'test/', TestView.as_view({'get':'list'}), name='test'), url(r'detail/(?P<pk>\d+)/', TestView.as_view({'get':'list'}), name='xxxx'), ]
from rest_framework import viewsets from rest_framework.response import Response class TestView(viewsets.GenericViewSet): def list(self, request, *args, **kwargs): return Response('...') def add(self, request, *args, **kwargs): pass
def delete(self, request, *args, **kwargs): pass
def edit(self, request, *args, **kwargs): pass
b. ModelViewSet(自定义URL)
from django.conf.urls import url, include from web.views import s10_generic urlpatterns = [ 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'})), ]
from rest_framework.viewsets import ModelViewSet from rest_framework import serializers from .. import models class 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 views router = routers.DefaultRouter() router.register(r'users', views.UserViewSet) router.register(r'groups', views.GroupViewSet) urlpatterns = [ url(r'^', include(router.urls)), ]
from rest_framework import viewsets from rest_framework import serializers class 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 = UserSerializer class GroupViewSet(viewsets.ModelViewSet): """ API endpoint that allows groups to be viewed or edited. """ queryset = Group.objects.all() serializer_class = GroupSerializer
十一、渲染器
根据 用户请求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 rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializers from 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, ] def get(self, request, *args, **kwargs): user_list = models.UserInfo.objects.all() ser = TestSerializer(instance=user_list, many=True) return Response(ser.data)
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/
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializers from 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, ] def get(self, request, *args, **kwargs): user_list = models.UserInfo.objects.all() ser = TestSerializer(instance=user_list, many=True) return Response(ser.data)
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/
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializers from rest_framework.renderers import JSONRenderer from rest_framework.renderers import AdminRenderer from rest_framework.renderers import HTMLFormRenderer from .. import models class TestSerializer(serializers.ModelSerializer): class Meta: model = models.UserInfo fields = "__all__" class TestView(APIView): renderer_classes = [HTMLFormRenderer, ] def get(self, request, *args, **kwargs): user_list = models.UserInfo.objects.all().first() ser = TestSerializer(instance=user_list, many=False) return Response(ser.data)
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_render urlpatterns = [ url(r'^test/$', s11_render.TestView.as_view()), url(r'^test\.(?P<format>[a-z0-9]+)', s11_render.TestView.as_view()), ]
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import serializers from rest_framework.renderers import TemplateHTMLRenderer from .. import models class TestSerializer(serializers.ModelSerializer): class Meta: model = models.UserInfo fields = "__all__" class TestView(APIView): renderer_classes = [TemplateHTMLRenderer, ] def get(self, request, *args, **kwargs): user_list = models.UserInfo.objects.all().first() ser = TestSerializer(instance=user_list, many=False) return Response(ser.data, template_name='user_detail.html')
<!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 serializers from rest_framework.renderers import JSONRenderer from rest_framework.renderers import BrowsableAPIRenderer from .. 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, ] def get(self, request, *args, **kwargs): user_list = models.UserInfo.objects.all().first() ser = TestSerializer(instance=user_list, many=False) return Response(ser.data, template_name='user_detail.html') 复制代码
注意:若是同时多个存在时,自动根据URL后缀来选择渲染器。
总结1: RESTful的执行流程
一、用户请求到达路由系统-----路由系统经过as_view()找到dispatch方法
二、dispatch方法对request数据进行二次封装,request数据的二次分装以后获得的是个对象列表,而后把每个对象(对象列表是从renderer_classes,parser_classes,authentication_classes,
throttle_classes,permission_classes,versioning_class类中拿的,若是咱们在视图类函数中没有重写该类方法,就会走默认的类下的方法。)列表赋值给request
三、执行initial方法,该方法主要是处理版本,认证,权限,节流等相关操做,主要是执行对象下的等相关类下的方法,也就是在第二步为咱们分装好了的方法。
四、根据反射找到对应的类(本身写的类方法)而后实例化执行类,获得response返回值,而后返回这个返回值给客户端
五、执行流程如图所示:咱们手动的操做主要是在步骤二中进行,即在view中重写他所提供的默认的类方法,执行完步骤三就至关于将认证相关的方法和调用相关的方法都封装到了request中
总体流程 第三部initial流程
总结2:
0、version方法直接配置全局或者局部参数便可
一、authentication方法只须要返回一个元组表示认证经过,返回一个None表示匿名用户登录,触发一个异常表示认证不经过
二、permissions方法返回一个True表示有权访问,返回一个Flase表示武器访问
三、throttling方法返回一个True则能够访问,若是为Flase则不能够访问
总结3:RESTful中视图类的继承关系