Django REST

一.什么是RESTful

  • REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”
  • REST从资源的角度类审视整个网络,它将分布在网络中某个节点的资源通过URL进行标识,客户端应用通过URL来获取资源的表征,获得这些表征致使这些应用转变状态
  • REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”
  • 所有的数据,不过是通过网络获取的还是操作(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其他架构风格的最本质属性
  • 对于REST这种面向资源的架构风格,有人提出一种全新的结构理念,即:面向资源架构(ROA:Resource Oriented Architecture)

二.RESTful API设计

  • API与用户的通信协议,总是使用HTTPs协议

  • 域名 

  • 版本

    • URL,如:https://api.example.com/v1/
    • 请求头                                                  跨域时,引发发送多次请求
  • 路径,视网络上任何东西都是资源,均使用名词表示(可复数)

  • method

    • GET      :从服务器取出资源(一项或多项)
    • POST    :在服务器新建一个资源
    • PUT      :在服务器更新资源(客户端提供改变后的完整资源)
    • PATCH  :在服务器更新资源(客户端提供改变的属性)
    • DELETE :从服务器删除资源
  • 过滤,通过在url上传参的形式传递搜索条件

  • 状态码

    • 1OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。 2CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。 3Accepted - [*]:表示一个请求已经进入后台排队(异步任务) 4NO CONTENT - [DELETE]:用户删除数据成功。 5INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。 6Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。 7Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。 8NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。 9Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。 10Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。 11Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。 12INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。 13 14更多看这里:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 15 16常用状态码列表

      常见的状态码

  •  错误处理,状态码是4__时,一般返回的都是错误信息,error为key

    • 1 { 2 error: "Invalid API key" 3 }
  • 返回结果,针对不同操作,服务器向用户返回的结果应该符合以下规范

    • 1 GET /collection:返回资源对象的列表(数组) 2 GET /collection/resource:返回单个资源对象 3 POST /collection:返回新生成的资源对象 4 PUT /collection/resource:返回完整的资源对象 5 PATCH /collection/resource:返回完整的资源对象 6 DELETE /collection/resource:返回一个空文档
  • Hypermedia API,RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。

    • 1 {"link": { 2 "rel": "collection https://www.example.com/zoos", 3 "href": "https://api.example.com/zoos", 4 "title": "List of zoos", 5 "type": "application/vnd.yourformat+json" 6 }}

三.基于Django实现

路由系统

1urlpatterns = [ 2 url(r'^users', Users.as_view()), 3]

CBV视图

1from django.views import View 2from django.http import JsonResponse 3 4class Users(View): 5 def get(self, request, *args, **kwargs): 6 result = { 7 'status': True, 8 'data': 'response data' 9 } 10 return JsonResponse(result, status=200) 11 12 def post(self, request, *args, **kwargs): 13 result = { 14 'status': True, 15 'data': 'response data' 16 } 17 return JsonResponse(result, status=200)

四. 基于Django Rest Framework框架实现

1. 基本流程

url.py

1from django.conf.urls import url, include 2from web.views.s1_api import TestView 3 4urlpatterns = [ 5 url(r'^test/', TestView.as_view()), 6]

views.py

1from rest_framework.views import APIView 2from rest_framework.response import Response 3 4 5class TestView(APIView): 6 def dispatch(self, request, *args, **kwargs): 7 """ 8 请求到来之后,都要执行dispatch方法,dispatch方法根据请求方式不同触发 get/post/put等方法 9 10 注意:APIView中的dispatch方法有好多好多的功能 11 """ 12 return super().dispatch(request, *args, **kwargs) 13 14 def get(self, request, *args, **kwargs): 15 return Response('GET请求,响应内容') 16 17 def post(self, request, *args, **kwargs): 18 return Response('POST请求,响应内容') 19 20 def put(self, request, *args, **kwargs): 21 return Response('PUT请求,响应内容')

上述是rest framework框架基本流程,重要的功能是在APIView的dispatch中触发。

2.  认证和授权

a. 用户url传入的token认证

1from django.conf.urls import url, include 2from web.viewsimport TestView 3 4urlpatterns = [ 5 url(r'^test/', TestView.as_view()), 6]

urls.py

1from rest_framework.views import APIView 2from rest_framework.response import Response 3from rest_framework.authentication import BaseAuthentication 4from rest_framework.request import Request 5from rest_framework import exceptions 6 7token_list = [ 8 'sfsfss123kuf3j123', 9 'asijnfowerkkf9812', 10] 11 12 13class 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 50class 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请求,响应内容')

views.py

b. 请求头认证

1from django.conf.urls import url, include 2from web.viewsimport TestView 3 4urlpatterns = [ 5 url(r'^test/', TestView.as_view()), 6]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5from rest_framework.authentication import BaseAuthentication 6from rest_framework.request import Request 7from rest_framework import exceptions 8 9token_list = [ 10 'sfsfss123kuf3j123', 11 'asijnfowerkkf9812', 12] 13 14 15class TestAuthentication(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() 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 auth = auth.split() 41 if not auth or auth[0].lower() != b'basic': 42 raise exceptions.AuthenticationFailed('验证失败') 43 if len(auth) != 2: 44 raise exceptions.AuthenticationFailed('验证失败') 45 username, part, password = base64.b64decode(auth[1]).decode('utf-8').partition(':') 46 if username == 'alex' and password == '123': 47 return ('登录用户', '用户token') 48 else: 49 raise exceptions.AuthenticationFailed('用户名或密码错误') 50 51 def authenticate_header(self, request): 52 """ 53 Return a string to be used as the value of the `WWW-Authenticate` 54 header in a `401 Unauthenticated` response, or `None` if the 55 authentication scheme should return `403 Permission Denied` responses. 56 """ 57 return 'Basic realm=api' 58 59 60class TestView(APIView): 61 authentication_classes = [TestAuthentication, ] 62 permission_classes = [] 63 64 def get(self, request, *args, **kwargs): 65 print(request.user) 66 print(request.auth) 67 return Response('GET请求,响应内容') 68 69 def post(self, request, *args, **kwargs): 70 return Response('POST请求,响应内容') 71 72 def put(self, request, *args, **kwargs): 73 return Response('PUT请求,响应内容')

views.py

c. 多个认证规则

1from django.conf.urls import url, include 2from web.views.s2_auth import TestView 3 4urlpatterns = [ 5 url(r'^test/', TestView.as_view()), 6]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5from rest_framework.authentication import BaseAuthentication 6from rest_framework.request import Request 7from rest_framework import exceptions 8 9token_list = [ 10 'sfsfss123kuf3j123', 11 'asijnfowerkkf9812', 12] 13 14 15class 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 63class 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 99class 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请求,响应内容')

views.py

d. 认证和权限

1from django.conf.urls import url, include 2from web.views import TestView 3 4urlpatterns = [ 5 url(r'^test/', TestView.as_view()), 6]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5from rest_framework.authentication import BaseAuthentication 6from rest_framework.permissions import BasePermission 7 8from rest_framework.request import Request 9from rest_framework import exceptions 10 11token_list = [ 12 'sfsfss123kuf3j123', 13 'asijnfowerkkf9812', 14] 15 16 17class 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 53class 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 81class 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请求,响应内容')

views.py

e. 全局使用

上述操作中均是对单独视图进行特殊配置,如果想要对全局进行配置,则需要再配置文件中写入即可。

1REST_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}

settings.py

1from django.conf.urls import url, include 2from web.views import TestView 3 4urlpatterns = [ 5 url(r'^test/', TestView.as_view()), 6]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5 6class 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请求,响应内容')

views.py

3. 用户访问次数/频率限制

a. 基于用户IP限制访问频率

1from django.conf.urls import url, include 2from web.views import TestView 3 4urlpatterns = [ 5 url(r'^test/', TestView.as_view()), 6]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3import time 4from rest_framework.views import APIView 5from rest_framework.response import Response 6 7from rest_framework import exceptions 8from rest_framework.throttling import BaseThrottle 9from rest_framework.settings import api_settings 10 11# 保存访问记录 12RECORD = { 13 '用户IP': [12312139, 12312135, 12312133, ] 14} 15 16 17class 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 # 获取用户唯一标识(如:IP49 50 # 允许一分钟访问1051 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 78class 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)

views.py

b. 基于用户IP显示访问频率(利于Django缓存)

1REST_FRAMEWORK = { 2 'DEFAULT_THROTTLE_RATES': { 3 'test_scope': '10/m', 4 }, 5}

settings.py

1from django.conf.urls import url, include 2from web.views import TestView 3 4urlpatterns = [ 5 url(r'^test/', TestView.as_view()), 6]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5 6from rest_framework import exceptions 7from rest_framework.throttling import SimpleRateThrottle 8 9 10class TestThrottle(SimpleRateThrottle): 11 12 # 配置文件定义的显示频率的Key 13 scope = "test_scope" 14 15 def get_cache_key(self, request, view): 16 """ 17 Should return a unique cache-key which can be used for throttling. 18 Must be overridden. 19 20 May return `None` if the request should not be throttled. 21 """ 22 if not request.user: 23 ident = self.get_ident(request) 24 else: 25 ident = request.user 26 27 return self.cache_format % { 28 'scope': self.scope, 29 'ident': ident 30 } 31 32 33class TestView(APIView): 34 throttle_classes = [TestThrottle, ] 35 36 def get(self, request, *args, **kwargs): 37 # self.dispatch 38 print(request.user) 39 print(request.auth) 40 return Response('GET请求,响应内容') 41 42 def post(self, request, *args, **kwargs): 43 return Response('POST请求,响应内容') 44 45 def put(self, request, *args, **kwargs): 46 return Response('PUT请求,响应内容') 47 48 def throttled(self, request, wait): 49 """ 50 访问次数被限制时,定制错误信息 51 """ 52 53 class Throttled(exceptions.Throttled): 54 default_detail = '请求被限制.' 55 extra_detail_singular = '请 {wait} 秒之后再重试.' 56 extra_detail_plural = '请 {wait} 秒之后再重试.' 57 58 raise Throttled(wait)

views.py

c. view中限制请求频率

1REST_FRAMEWORK = { 2 'DEFAULT_THROTTLE_RATES': { 3 'xxxxxx': '10/m', 4 }, 5}

settings.py

1from django.conf.urls import url, include 2from web.views import TestView 3 4urlpatterns = [ 5 url(r'^test/', TestView.as_view()), 6]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5 6from rest_framework import exceptions 7from rest_framework.throttling import ScopedRateThrottle 8 9 10# 继承 ScopedRateThrottle 11class 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 31class 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)

views.py

d. 匿名时用IP限制+登录时用Token限制

1REST_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}

settings.py

1from django.conf.urls import url, include 2from web.views.s3_throttling import TestView 3 4urlpatterns = [ 5 url(r'^test/', TestView.as_view()), 6]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5 6from rest_framework.throttling import SimpleRateThrottle 7 8 9class 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 26class 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 58class 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请求,响应内容')

views.py

e. 全局使用

1REST_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}

settings

4. 版本

a. 基于url的get传参方式

如:/users?version=v1

1REST_FRAMEWORK = { 2 'DEFAULT_VERSION': 'v1', # 默认版本 3 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本 4 'VERSION_PARAM': 'version' # URL中获取值的key 5}

settings.py

1from django.conf.urls import url, include 2from web.views import TestView 3 4urlpatterns = [ 5 url(r'^test/', TestView.as_view(),name='test'), 6]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5from rest_framework.versioning import QueryParameterVersioning 6 7 8class 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请求,响应内容')

views.py

b. 基于url的正则方式

如:/v1/users/

1REST_FRAMEWORK = { 2 'DEFAULT_VERSION': 'v1', # 默认版本 3 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本 4 'VERSION_PARAM': 'version' # URL中获取值的key 5}

settings.py

1from django.conf.urls import url, include 2from web.views import TestView 3 4urlpatterns = [ 5 url(r'^(?P<version>[v1|v2]+)/test/', TestView.as_view(), name='test'), 6]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5from rest_framework.versioning import URLPathVersioning 6 7 8class 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请求,响应内容')

views.py

c. 基于 accept 请求头方式

如:Accept: application/json; version=1.0

1REST_FRAMEWORK = { 2 'DEFAULT_VERSION': 'v1', # 默认版本 3 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本 4 'VERSION_PARAM': 'version' # URL中获取值的key 5}

settings.py

1from django.conf.urls import url, include 2from web.views import TestView 3 4urlpatterns = [ 5 url(r'^test/', TestView.as_view(), name='test'), 6]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5from rest_framework.versioning import AcceptHeaderVersioning 6 7 8class TestView(APIView): 9 versioning_class = AcceptHeaderVersioning 10 11 def get(self, request, *args, **kwargs): 12 # 获取版本 HTTP_ACCEPT13 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请求,响应内容')

views.py

d. 基于主机名方法

如:v1.example.com

1ALLOWED_HOSTS = ['*'] 2REST_FRAMEWORK = { 3 'DEFAULT_VERSION': 'v1', # 默认版本 4 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本 5 'VERSION_PARAM': 'version' # URL中获取值的key 6}

settings.py

1from django.conf.urls import url, include 2from web.views import TestView 3 4urlpatterns = [ 5 url(r'^test/', TestView.as_view(), name='test'), 6]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5from rest_framework.versioning import HostNameVersioning 6 7 8class 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请求,响应内容')

views.py

e. 基于django路由系统的namespace

如:example.com/v1/users/

1REST_FRAMEWORK = { 2 'DEFAULT_VERSION': 'v1', # 默认版本 3 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本 4 'VERSION_PARAM': 'version' # URL中获取值的key 5}

settings.py

1from django.conf.urls import url, include 2from web.views import TestView 3 4urlpatterns = [ 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]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5from rest_framework.versioning import NamespaceVersioning 6 7 8class 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请求,响应内容')

views.py

f. 全局使用

1REST_FRAMEWORK = { 2 'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning", 3 'DEFAULT_VERSION': 'v1', 4 'ALLOWED_VERSIONS': ['v1', 'v2'], 5 'VERSION_PARAM': 'version' 6}

settings.py

5. 解析器(parser) 

根据请求头 content-type 选择对应的解析器就请求体内容进行处理。

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

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

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5from rest_framework.request import Request 6from rest_framework.parsers import JSONParser 7 8 9class 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请求,响应内容')

views.py

b. 仅处理请求头content-type为application/x-www-form-urlencoded 的请求体

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

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5from rest_framework.request import Request 6from rest_framework.parsers import FormParser 7 8 9class 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请求,响应内容')

views.py

c. 仅处理请求头content-type为multipart/form-data的请求体

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

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5from rest_framework.request import Request 6from rest_framework.parsers import MultiPartParser 7 8 9class 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请求,响应内容')

views.py

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>

upload.html

d. 仅上传文件

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

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5from rest_framework.request import Request 6from rest_framework.parsers import FileUploadParser 7 8 9class 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请求,响应内容')

views.py

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>

upload.html

e. 同时多个Parser

当同时使用多个parser时,rest framework会根据请求头content-type自动进行比对,并使用对应parser

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

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5from rest_framework.request import Request 6from rest_framework.parsers import JSONParser, FormParser, MultiPartParser 7 8 9class 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请求,响应内容')

views.py

f. 全局使用

1REST_FRAMEWORK = { 2 'DEFAULT_PARSER_CLASSES':[ 3 'rest_framework.parsers.JSONParser' 4 'rest_framework.parsers.FormParser' 5 'rest_framework.parsers.MultiPartParser' 6 ] 7 8}

settings.py

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

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5 6 7class TestView(APIView): 8 def post(self, request, *args, **kwargs): 9 print(request.content_type) 10 11 # 获取请求的值,并使用对应的JSONParser进行处理 12 print(request.data) 13 # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值 14 print(request.POST) 15 print(request.FILES) 16 return Response('POST请求,响应内容') 17 18 def put(self, request, *args, **kwargs): 19 return Response('PUT请求,响应内容')

views.py

注意:个别特殊的值可以通过Django的request对象 request._request 来进行获取

6. 序列化

序列化用于对用户请求数据进行验证和数据进行序列化。

a. 自定义字段

1from django.conf.urls import url, include 2from web.views.s6_serializers import TestView 3 4urlpatterns = [ 5 url(r'test/', TestView.as_view(), name='test'), 6]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5from rest_framework import serializers 6from .. import models 7 8 9class 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 27class 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 33class 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请求,响应内容')

views.py

b. 基于Model自动生成字段

1from django.conf.urls import url, include 2from web.views.s6_serializers import TestView 3 4urlpatterns = [ 5 url(r'test/', TestView.as_view(), name='test'), 6]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5from rest_framework import serializers 6from .. import models 7 8 9class 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 26class 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 39class 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请求,响应内容')

views.py

c. 生成URL

1from django.conf.urls import url, include 2from web.views.s6_serializers import TestView 3 4urlpatterns = [ 5 url(r'test/', TestView.as_view(), name='test'), 6 url(r'detail/(?P<pk>\d+)/', TestView.as_view(), name='detail'), 7]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5from rest_framework import serializers 6from .. import models 7 8 9class 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 27class 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 40class 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请求,响应内容')

views.py

d. 自动生成URL

1from django.conf.urls import url, include 2from web.views.s6_serializers import TestView 3 4urlpatterns = [ 5 url(r'test/', TestView.as_view(), name='test'), 6 url(r'detail/(?P<pk>\d+)/', TestView.as_view(), name='xxxx'), 7]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5from rest_framework import serializers 6from .. import models 7 8 9class 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 27class 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 44class 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请求,响应内容')

views.py

7. 分页

a. 根据页码进行分页

1from django.conf.urls import url, include 2from rest_framework import routers 3from web.views import s9_pagination 4 5urlpatterns = [ 6 url(r'^test/', s9_pagination.UserViewSet.as_view()), 7]

urs.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework import serializers 5from .. import models 6 7from rest_framework.pagination import PageNumberPagination 8 9 10class 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 23class UserSerializer(serializers.ModelSerializer): 24 class Meta: 25 model = models.UserInfo 26 fields = "__all__" 27 28 29class 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

views.py

b. 位置和个数进行分页

1from django.conf.urls import url, include 2from web.views import s9_pagination 3 4urlpatterns = [ 5 url(r'^test/', s9_pagination.UserViewSet.as_view()), 6]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework import serializers 5from .. import models 6 7from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination 8 9 10class 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 20class UserSerializer(serializers.ModelSerializer): 21 class Meta: 22 model = models.UserInfo 23 fields = "__all__" 24 25 26class 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

views.py

c. 游标分页

1from django.conf.urls import url, include 2from web.views import s9_pagination 3 4urlpatterns = [ 5 url(r'^test/', s9_pagination.UserViewSet.as_view()), 6]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework import serializers 5from .. import models 6 7from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination 8 9 10class 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 25class UserSerializer(serializers.ModelSerializer): 26 class Meta: 27 model = models.UserInfo 28 fields = "__all__" 29 30 31class 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

views.py

8. 路由系统

a. 自定义路由

1from django.conf.urls import url, include 2from web.views import s11_render 3 4urlpatterns = [ 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]

urls.py

1from rest_framework.views import APIView 2from rest_framework.response import Response 3from .. import models 4 5 6class TestView(APIView): 7 def get(self, request, *args, **kwargs): 8 print(kwargs) 9 print(self.renderer_classes) 10 return Response('...')

views.py

b. 半自动路由

1from django.conf.urls import url, include 2from web.views import s10_generic 3 4urlpatterns = [ 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]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.viewsets import ModelViewSet 4from rest_framework import serializers 5from .. import models 6 7 8class UserSerializer(serializers.ModelSerializer): 9 class Meta: 10 model = models.UserInfo 11 fields = "__all__" 12 13 14class UserViewSet(ModelViewSet): 15 queryset = models.UserInfo.objects.all() 16 serializer_class = UserSerializer

views.py

c. 全自动路由

1from django.conf.urls import url, include 2from rest_framework import routers 3from web.views import s10_generic 4 5 6router = routers.DefaultRouter() 7router.register(r'users', s10_generic.UserViewSet) 8 9urlpatterns = [ 10 url(r'^', include(router.urls)), 11]

urls.py

1from rest_framework.viewsets import ModelViewSet 2from rest_framework import serializers 3from .. import models 4 5 6class UserSerializer(serializers.ModelSerializer): 7 class Meta: 8 model = models.UserInfo 9 fields = "__all__" 10 11 12class UserViewSet(ModelViewSet): 13 queryset = models.UserInfo.objects.all() 14 serializer_class = UserSerializer

views.py

9. 视图

a. GenericViewSet

1from django.conf.urls import url, include 2from web.views.s7_viewset import TestView 3 4urlpatterns = [ 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]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework import viewsets 4from rest_framework.response import Response 5 6 7class 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

views.py

b. ModelViewSet(自定义URL)

1from django.conf.urls import url, include 2from web.views import s10_generic 3 4urlpatterns = [ 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]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.viewsets import ModelViewSet 4from rest_framework import serializers 5from .. import models 6 7 8class UserSerializer(serializers.ModelSerializer): 9 class Meta: 10 model = models.UserInfo 11 fields = "__all__" 12 13 14class UserViewSet(ModelViewSet): 15 queryset = models.UserInfo.objects.all() 16 serializer_class = UserSerializer

views.py

c. ModelViewSet(rest framework路由)

1from django.conf.urls import url, include 2from rest_framework import routers 3from app01 import views 4 5router = routers.DefaultRouter() 6router.register(r'users', views.UserViewSet) 7router.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. 11urlpatterns = [ 12 url(r'^', include(router.urls)), 13]

urls.py

1from rest_framework import viewsets 2from rest_framework import serializers 3 4 5class UserSerializer(serializers.HyperlinkedModelSerializer): 6 class Meta: 7 model = models.User 8 fields = ('url', 'username', 'email', 'groups') 9 10 11class GroupSerializer(serializers.HyperlinkedModelSerializer): 12 class Meta: 13 model = models.Group 14 fields = ('url', 'name') 15 16class 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 24class 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

views.py

10. 渲染器

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

用户请求头:

  • Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8

a. json

访问URL:

1from django.conf.urls import url, include 2from web.views import s11_render 3 4urlpatterns = [ 5 url(r'^test/$', s11_render.TestView.as_view()), 6 url(r'^test\.(?P<format>[a-z0-9]+)', s11_render.TestView.as_view()), 7]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5from rest_framework import serializers 6 7from rest_framework.renderers import JSONRenderer 8 9from .. import models 10 11 12class TestSerializer(serializers.ModelSerializer): 13 class Meta: 14 model = models.UserInfo 15 fields = "__all__" 16 17 18class 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)

views.py

b. 表格

访问URL:

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5from rest_framework import serializers 6 7from rest_framework.renderers import AdminRenderer 8 9from .. import models 10 11 12class TestSerializer(serializers.ModelSerializer): 13 class Meta: 14 model = models.UserInfo 15 fields = "__all__" 16 17 18class 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)

views.py

c. Form表单

访问URL:

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5from rest_framework import serializers 6 7from rest_framework.renderers import JSONRenderer 8from rest_framework.renderers import AdminRenderer 9from rest_framework.renderers import HTMLFormRenderer 10 11from .. import models 12 13 14class TestSerializer(serializers.ModelSerializer): 15 class Meta: 16 model = models.UserInfo 17 fields = "__all__" 18 19 20class 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)

views.py

d. 自定义显示模板

访问URL:

1from django.conf.urls import url, include 2from web.views import s11_render 3 4urlpatterns = [ 5 url(r'^test/$', s11_render.TestView.as_view()), 6 url(r'^test\.(?P<format>[a-z0-9]+)', s11_render.TestView.as_view()), 7]

urls.py

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5from rest_framework import serializers 6from rest_framework.renderers import TemplateHTMLRenderer 7 8from .. import models 9 10 11class TestSerializer(serializers.ModelSerializer): 12 class Meta: 13 model = models.UserInfo 14 fields = "__all__" 15 16 17class 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')

views.py

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>

userdetail.html

e. 浏览器格式API+JSON

访问URL:

1#!/usr/bin/env python 2# -*- coding:utf-8 -*- 3from rest_framework.views import APIView 4from rest_framework.response import Response 5from rest_framework import serializers 6 7from rest_framework.renderers import JSONRenderer 8from rest_framework.renderers import BrowsableAPIRenderer 9 10from .. import models 11 12 13class TestSerializer(serializers.ModelSerializer): 14 class Meta: 15 model = models.UserInfo 16 fields = "__all__" 17 18 19class CustomBrowsableAPIRenderer(BrowsableAPIRenderer): 20 def get_default_renderer(self, view): 21 return JSONRenderer() 22 23 24class 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')

views.py

注意:如果同时多个存在时,自动根据URL后缀来选择渲染器。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

Django REST - HelloWorld