Django之Rest Framework框架

一、什么是RESTful

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

二、RESTful API设计

  • API与用户的通信协议,总是使用HTTPs协议
  • 域名 
    • https://api.example.com                         尽量将API部署在专用域名(会存在跨域问题)
    • https://example.org/api/                        API很简单
  • 版本
    • URL,如:https://api.example.com/v1/
    • 请求头                                                  跨域时,引发发送多次请求
  • 路径,视网络上任何东西都是资源,均使用名词表示(可复数)
    • https://api.example.com/v1/zoos
    • https://api.example.com/v1/animals
    • https://api.example.com/v1/employees
  • method
    • GET      :从服务器取出资源(一项或多项)
    • POST    :在服务器新建一个资源
    • PUT      :在服务器更新资源(客户端提供改变后的完整资源)
    • PATCH  :在服务器更新资源(客户端提供改变的属性)
    • DELETE :从服务器删除资源
  • 过滤,通过在url上传参的形式传递搜索条件
    • https://api.example.com/v1/zoos?limit=10:指定返回记录的数量
    • https://api.example.com/v1/zoos?offset=10:指定返回记录的开始位置
    • https://api.example.com/v1/zoos?page=2&per_page=100:指定第几页,以及每页的记录数
    • https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序
    • https://api.example.com/v1/zoos?animal_type_id=1:指定筛选条件
  • 状态码
200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
204 NO CONTENT - [DELETE]:用户删除数据成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。

更多看这里:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
  • 错误处理,状态码是4xx时,应返回错误信息,error当做key。
{
    error: "Invalid API key"
}
  • 返回结果,针对不同操作,服务器向用户返回的结果应该符合以下规范。
GET /collection:返回资源对象的列表(数组)
GET /collection/resource:返回单个资源对象
POST /collection:返回新生成的资源对象
PUT /collection/resource:返回完整的资源对象
PATCH /collection/resource:返回完整的资源对象
DELETE /collection/resource:返回一个空文档
  • Hypermedia API,RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。
{"link": {
  "rel":   "collection https://www.example.com/zoos",
  "href":  "https://api.example.com/zoos",
  "title": "List of zoos",
  "type":  "application/vnd.yourformat+json"
}}

  摘自:http://www.ruanyifeng.com/blog/2014/05/restful_api.html 

三、基于Django实现

路由系统:

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

CBV视图:

from django.views import View
from django.http import JsonResponse
 
class Users(View):
    def get(self, request, *args, **kwargs):
        result = {
            'status': True,
            'data': 'response data'
        }
        return JsonResponse(result, status=200)
 
    def post(self, request, *args, **kwargs):
        result = {
            'status': True,
            'data': 'response data'
        }
        return JsonResponse(result, status=200) 

 四、基于Django Rest Framework框架实现

4.1基本流程

url.py

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

views.py

from rest_framework.views import APIView
from rest_framework.response import Response
 
 
class TestView(APIView):
    def dispatch(self, request, *args, **kwargs):
        """
        请求到来之后,都要执行dispatch方法,dispatch方法根据请求方式不同触发 get/post/put等方法
         
        注意:APIView中的dispatch方法有好多好多的功能
        """
        return super().dispatch(request, *args, **kwargs)
 
    def get(self, request, *args, **kwargs):
        return Response('GET请求,响应内容')
 
    def post(self, request, *args, **kwargs):
        return Response('POST请求,响应内容')
 
    def put(self, request, *args, **kwargs):
        return Response('PUT请求,响应内容')

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

4.2认证和授权

1、用户url传入的token认证

url.py

from django.conf.urls import url, include
from web.viewsimport TestView

urlpatterns = [
    url(r'^test/', TestView.as_view()),
]
 1 from rest_framework.views import APIView
 2 from rest_framework.response import Response
 3 from rest_framework.authentication import BaseAuthentication
 4 from rest_framework.request import Request
 5 from rest_framework import exceptions
 6 
 7 token_list = [
 8     'sfsfss123kuf3j123',
 9     'asijnfowerkkf9812',
10 ]
11 
12 
13 class TestAuthentication(BaseAuthentication):
14     def authenticate(self, request):
15         """
16         用户认证,如果验证成功后返回元组: (用户,用户Token)
17         :param request: 
18         :return: 
19             None,表示跳过该验证;
20                 如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
21                 self._authenticator = None
22                 if api_settings.UNAUTHENTICATED_USER:
23                     self.user = api_settings.UNAUTHENTICATED_USER()
24                 else:
25                     self.user = None
26         
27                 if api_settings.UNAUTHENTICATED_TOKEN:
28                     self.auth = api_settings.UNAUTHENTICATED_TOKEN()
29                 else:
30                     self.auth = None
31             (user,token)表示验证通过并设置用户名和Token;
32             AuthenticationFailed异常
33         """
34         val = request.query_params.get('token')
35         if val not in token_list:
36             raise exceptions.AuthenticationFailed("用户认证失败")
37 
38         return ('登录用户', '用户token')
39 
40     def authenticate_header(self, request):
41         """
42         Return a string to be used as the value of the `WWW-Authenticate`
43         header in a `401 Unauthenticated` response, or `None` if the
44         authentication scheme should return `403 Permission Denied` responses.
45         """
46         # 验证失败时,返回的响应头WWW-Authenticate对应的值
47         pass
48 
49 
50 class TestView(APIView):
51     authentication_classes = [TestAuthentication, ]
52     permission_classes = []
53 
54     def get(self, request, *args, **kwargs):
55         print(request.user)
56         print(request.auth)
57         return Response('GET请求,响应内容')
58 
59     def post(self, request, *args, **kwargs):
60         return Response('POST请求,响应内容')
61 
62     def put(self, request, *args, **kwargs):
63         return Response('PUT请求,响应内容')
views.py

2、请求头认证

1 from django.conf.urls import url, include
2 from web.viewsimport TestView
3 
4 urlpatterns = [
5     url(r'^test/', TestView.as_view()),
6 ]
url.py
 1 from rest_framework.views import APIView
 2 from rest_framework.response import Response
 3 from rest_framework.authentication import BaseAuthentication
 4 from rest_framework.request import Request
 5 from rest_framework import exceptions
 6 
 7 token_list = [
 8     'sfsfss123kuf3j123',
 9     'asijnfowerkkf9812',
10 ]
11 
12 
13 class TestAuthentication(BaseAuthentication):
14     def authenticate(self, request):
15         """
16         用户认证,如果验证成功后返回元组: (用户,用户Token)
17         :param request: 
18         :return: 
19             None,表示跳过该验证;
20                 如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
21                 self._authenticator = None
22                 if api_settings.UNAUTHENTICATED_USER:
23                     self.user = api_settings.UNAUTHENTICATED_USER()
24                 else:
25                     self.user = None
26         
27                 if api_settings.UNAUTHENTICATED_TOKEN:
28                     self.auth = api_settings.UNAUTHENTICATED_TOKEN()
29                 else:
30                     self.auth = None
31             (user,token)表示验证通过并设置用户名和Token;
32             AuthenticationFailed异常
33         """
34         import base64
35         auth = request.META.get('HTTP_AUTHORIZATION', b'')
36         if auth:
37             auth = auth.encode('utf-8')
38         auth = auth.split()
39         if not auth or auth[0].lower() != b'basic':
40             raise exceptions.AuthenticationFailed('验证失败')
41         if len(auth) != 2:
42             raise exceptions.AuthenticationFailed('验证失败')
43         username, part, password = base64.b64decode(auth[1]).decode('utf-8').partition(':')
44         if username == 'alex' and password == '123':
45             return ('登录用户', '用户token')
46         else:
47             raise exceptions.AuthenticationFailed('用户名或密码错误')
48 
49     def authenticate_header(self, request):
50         """
51         Return a string to be used as the value of the `WWW-Authenticate`
52         header in a `401 Unauthenticated` response, or `None` if the
53         authentication scheme should return `403 Permission Denied` responses.
54         """
55         return 'Basic realm=api'
56 
57 
58 class TestView(APIView):
59     authentication_classes = [TestAuthentication, ]
60     permission_classes = []
61 
62     def get(self, request, *args, **kwargs):
63         print(request.user)
64         print(request.auth)
65         return Response('GET请求,响应内容')
66 
67     def post(self, request, *args, **kwargs):
68         return Response('POST请求,响应内容')
69 
70     def put(self, request, *args, **kwargs):
71         return Response('PUT请求,响应内容')
views.py

3、多个认证规则

1 from django.conf.urls import url, include
2 from web.views.s2_auth import TestView
3 
4 urlpatterns = [
5     url(r'^test/', TestView.as_view()),
6 ]
urls.py
  1 #!/usr/bin/env python
  2 # -*- coding:utf-8 -*-
  3 from rest_framework.views import APIView
  4 from rest_framework.response import Response
  5 from rest_framework.authentication import BaseAuthentication
  6 from rest_framework.request import Request
  7 from rest_framework import exceptions
  8 
  9 token_list = [
 10     'sfsfss123kuf3j123',
 11     'asijnfowerkkf9812',
 12 ]
 13 
 14 
 15 class Test1Authentication(BaseAuthentication):
 16     def authenticate(self, request):
 17         """
 18         用户认证,如果验证成功后返回元组: (用户,用户Token)
 19         :param request: 
 20         :return: 
 21             None,表示跳过该验证;
 22                 如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
 23                 self._authenticator = None
 24                 if api_settings.UNAUTHENTICATED_USER:
 25                     self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户
 26                 else:
 27                     self.user = None
 28 
 29                 if api_settings.UNAUTHENTICATED_TOKEN:
 30                     self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默认值为:None
 31                 else:
 32                     self.auth = None
 33             (user,token)表示验证通过并设置用户名和Token;
 34             AuthenticationFailed异常
 35         """
 36         import base64
 37         auth = request.META.get('HTTP_AUTHORIZATION', b'')
 38         if auth:
 39             auth = auth.encode('utf-8')
 40         else:
 41             return None
 42         print(auth,'xxxx')
 43         auth = auth.split()
 44         if not auth or auth[0].lower() != b'basic':
 45             raise exceptions.AuthenticationFailed('验证失败')
 46         if len(auth) != 2:
 47             raise exceptions.AuthenticationFailed('验证失败')
 48         username, part, password = base64.b64decode(auth[1]).decode('utf-8').partition(':')
 49         if username == 'alex' and password == '123':
 50             return ('登录用户', '用户token')
 51         else:
 52             raise exceptions.AuthenticationFailed('用户名或密码错误')
 53 
 54     def authenticate_header(self, request):
 55         """
 56         Return a string to be used as the value of the `WWW-Authenticate`
 57         header in a `401 Unauthenticated` response, or `None` if the
 58         authentication scheme should return `403 Permission Denied` responses.
 59         """
 60         # return 'Basic realm=api'
 61         pass
 62 
 63 class Test2Authentication(BaseAuthentication):
 64     def authenticate(self, request):
 65         """
 66         用户认证,如果验证成功后返回元组: (用户,用户Token)
 67         :param request: 
 68         :return: 
 69             None,表示跳过该验证;
 70                 如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
 71                 self._authenticator = None
 72                 if api_settings.UNAUTHENTICATED_USER:
 73                     self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户
 74                 else:
 75                     self.user = None
 76         
 77                 if api_settings.UNAUTHENTICATED_TOKEN:
 78                     self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默认值为:None
 79                 else:
 80                     self.auth = None
 81             (user,token)表示验证通过并设置用户名和Token;
 82             AuthenticationFailed异常
 83         """
 84         val = request.query_params.get('token')
 85         if val not in token_list:
 86             raise exceptions.AuthenticationFailed("用户认证失败")
 87 
 88         return ('登录用户', '用户token')
 89 
 90     def authenticate_header(self, request):
 91         """
 92         Return a string to be used as the value of the `WWW-Authenticate`
 93         header in a `401 Unauthenticated` response, or `None` if the
 94         authentication scheme should return `403 Permission Denied` responses.
 95         """
 96         pass
 97 
 98 
 99 class TestView(APIView):
100     authentication_classes = [Test1Authentication, Test2Authentication]
101     permission_classes = []
102 
103     def get(self, request, *args, **kwargs):
104         print(request.user)
105         print(request.auth)
106         return Response('GET请求,响应内容')
107 
108     def post(self, request, *args, **kwargs):
109         return Response('POST请求,响应内容')
110 
111     def put(self, request, *args, **kwargs):
112         return Response('PUT请求,响应内容')
views.py

4、认证和权限

1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'^test/', TestView.as_view()),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework.authentication import BaseAuthentication
 6 from rest_framework.permissions import BasePermission
 7 
 8 from rest_framework.request import Request
 9 from rest_framework import exceptions
10 
11 token_list = [
12     'sfsfss123kuf3j123',
13     'asijnfowerkkf9812',
14 ]
15 
16 
17 class TestAuthentication(BaseAuthentication):
18     def authenticate(self, request):
19         """
20         用户认证,如果验证成功后返回元组: (用户,用户Token)
21         :param request: 
22         :return: 
23             None,表示跳过该验证;
24                 如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
25                 self._authenticator = None
26                 if api_settings.UNAUTHENTICATED_USER:
27                     self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户
28                 else:
29                     self.user = None
30         
31                 if api_settings.UNAUTHENTICATED_TOKEN:
32                     self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默认值为:None
33                 else:
34                     self.auth = None
35             (user,token)表示验证通过并设置用户名和Token;
36             AuthenticationFailed异常
37         """
38         val = request.query_params.get('token')
39         if val not in token_list:
40             raise exceptions.AuthenticationFailed("用户认证失败")
41 
42         return ('登录用户', '用户token')
43 
44     def authenticate_header(self, request):
45         """
46         Return a string to be used as the value of the `WWW-Authenticate`
47         header in a `401 Unauthenticated` response, or `None` if the
48         authentication scheme should return `403 Permission Denied` responses.
49         """
50         pass
51 
52 
53 class TestPermission(BasePermission):
54     message = "权限验证失败"
55 
56     def has_permission(self, request, view):
57         """
58         判断是否有权限访问当前请求
59         Return `True` if permission is granted, `False` otherwise.
60         :param request: 
61         :param view: 
62         :return: True有权限;False无权限
63         """
64         if request.user == "管理员":
65             return True
66 
67     # GenericAPIView中get_object时调用
68     def has_object_permission(self, request, view, obj):
69         """
70         视图继承GenericAPIView,并在其中使用get_object时获取对象时,触发单独对象权限验证
71         Return `True` if permission is granted, `False` otherwise.
72         :param request: 
73         :param view: 
74         :param obj: 
75         :return: True有权限;False无权限
76         """
77         if request.user == "管理员":
78             return True
79 
80 
81 class TestView(APIView):
82     # 认证的动作是由request.user触发
83     authentication_classes = [TestAuthentication, ]
84 
85     # 权限
86     # 循环执行所有的权限
87     permission_classes = [TestPermission, ]
88 
89     def get(self, request, *args, **kwargs):
90         # self.dispatch
91         print(request.user)
92         print(request.auth)
93         return Response('GET请求,响应内容')
94 
95     def post(self, request, *args, **kwargs):
96         return Response('POST请求,响应内容')
97 
98     def put(self, request, *args, **kwargs):
99         return Response('PUT请求,响应内容')
views.py

5、全局使用

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

 1 REST_FRAMEWORK = {
 2     'UNAUTHENTICATED_USER': None,
 3     'UNAUTHENTICATED_TOKEN': None,
 4     "DEFAULT_AUTHENTICATION_CLASSES": [
 5         "web.utils.TestAuthentication",
 6     ],
 7     "DEFAULT_PERMISSION_CLASSES": [
 8         "web.utils.TestPermission",
 9     ],
10 }
settings
1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'^test/', TestView.as_view()),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 
 6 class TestView(APIView):
 7 
 8     def get(self, request, *args, **kwargs):
 9         # self.dispatch
10         print(request.user)
11         print(request.auth)
12         return Response('GET请求,响应内容')
13 
14     def post(self, request, *args, **kwargs):
15         return Response('POST请求,响应内容')
16 
17     def put(self, request, *args, **kwargs):
18         return Response('PUT请求,响应内容')
views.py

4.3用户访问次数/频率限制

1、基于用户IP限制访问频率

1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'^test/', TestView.as_view()),
6 ]
urls.py
  1 #!/usr/bin/env python
  2 # -*- coding:utf-8 -*-
  3 import time
  4 from rest_framework.views import APIView
  5 from rest_framework.response import Response
  6 
  7 from rest_framework import exceptions
  8 from rest_framework.throttling import BaseThrottle
  9 from rest_framework.settings import api_settings
 10 
 11 # 保存访问记录
 12 RECORD = {
 13     '用户IP': [12312139, 12312135, 12312133, ]
 14 }
 15 
 16 
 17 class TestThrottle(BaseThrottle):
 18     ctime = time.time
 19 
 20     def get_ident(self, request):
 21         """
 22         根据用户IP和代理IP,当做请求者的唯一IP
 23         Identify the machine making the request by parsing HTTP_X_FORWARDED_FOR
 24         if present and number of proxies is > 0. If not use all of
 25         HTTP_X_FORWARDED_FOR if it is available, if not use REMOTE_ADDR.
 26         """
 27         xff = request.META.get('HTTP_X_FORWARDED_FOR')
 28         remote_addr = request.META.get('REMOTE_ADDR')
 29         num_proxies = api_settings.NUM_PROXIES
 30 
 31         if num_proxies is not None:
 32             if num_proxies == 0 or xff is None:
 33                 return remote_addr
 34             addrs = xff.split(',')
 35             client_addr = addrs[-min(num_proxies, len(addrs))]
 36             return client_addr.strip()
 37 
 38         return ''.join(xff.split()) if xff else remote_addr
 39 
 40     def allow_request(self, request, view):
 41         """
 42         是否仍然在允许范围内
 43         Return `True` if the request should be allowed, `False` otherwise.
 44         :param request: 
 45         :param view: 
 46         :return: True,表示可以通过;False表示已超过限制,不允许访问
 47         """
 48         # 获取用户唯一标识(如:IP)
 49 
 50         # 允许一分钟访问10次
 51         num_request = 10
 52         time_request = 60
 53 
 54         now = self.ctime()
 55         ident = self.get_ident(request)
 56         self.ident = ident
 57         if ident not in RECORD:
 58             RECORD[ident] = [now, ]
 59             return True
 60         history = RECORD[ident]
 61         while history and history[-1] <= now - time_request:
 62             history.pop()
 63         if len(history) < num_request:
 64             history.insert(0, now)
 65             return True
 66 
 67     def wait(self):
 68         """
 69         多少秒后可以允许继续访问
 70         Optionally, return a recommended number of seconds to wait before
 71         the next request.
 72         """
 73         last_time = RECORD[self.ident][0]
 74         now = self.ctime()
 75         return int(60 + last_time - now)
 76 
 77 
 78 class TestView(APIView):
 79     throttle_classes = [TestThrottle, ]
 80 
 81     def get(self, request, *args, **kwargs):
 82         # self.dispatch
 83         print(request.user)
 84         print(request.auth)
 85         return Response('GET请求,响应内容')
 86 
 87     def post(self, request, *args, **kwargs):
 88         return Response('POST请求,响应内容')
 89 
 90     def put(self, request, *args, **kwargs):
 91         return Response('PUT请求,响应内容')
 92 
 93     def throttled(self, request, wait):
 94         """
 95         访问次数被限制时,定制错误信息
 96         """
 97 
 98         class Throttled(exceptions.Throttled):
 99             default_detail = '请求被限制.'
100             extra_detail_singular = '请 {wait} 秒之后再重试.'
101             extra_detail_plural = '请 {wait} 秒之后再重试.'
102 
103         raise Throttled(wait)
views.py

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

1 REST_FRAMEWORK = {
2     'DEFAULT_THROTTLE_RATES': {
3         'test_scope': '10/m',
4     },
5 }
settings.py
1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'^test/', TestView.as_view()),
6 ]
urls.py
views.py

3、view中限制请求频率

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

4、匿名时用IP限制+登录时用Token限制

1 REST_FRAMEWORK = {
2     'UNAUTHENTICATED_USER': None,
3     'UNAUTHENTICATED_TOKEN': None,
4     'DEFAULT_THROTTLE_RATES': {
5         'luffy_anon': '10/m',
6         'luffy_user': '20/m',
7     },
8 }
settings.py
1 from django.conf.urls import url, include
2 from web.views.s3_throttling import TestView
3 
4 urlpatterns = [
5     url(r'^test/', TestView.as_view()),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 
 6 from rest_framework.throttling import SimpleRateThrottle
 7 
 8 
 9 class LuffyAnonRateThrottle(SimpleRateThrottle):
10     """
11     匿名用户,根据IP进行限制
12     """
13     scope = "luffy_anon"
14 
15     def get_cache_key(self, request, view):
16         # 用户已登录,则跳过 匿名频率限制
17         if request.user:
18             return None
19 
20         return self.cache_format % {
21             'scope': self.scope,
22             'ident': self.get_ident(request)
23         }
24 
25 
26 class LuffyUserRateThrottle(SimpleRateThrottle):
27     """
28     登录用户,根据用户token限制
29     """
30     scope = "luffy_user"
31 
32     def get_ident(self, request):
33         """
34         认证成功时:request.user是用户对象;request.auth是token对象
35         :param request: 
36         :return: 
37         """
38         # return request.auth.token
39         return "user_token"
40 
41     def get_cache_key(self, request, view):
42         """
43         获取缓存key
44         :param request: 
45         :param view: 
46         :return: 
47         """
48         # 未登录用户,则跳过 Token限制
49         if not request.user:
50             return None
51 
52         return self.cache_format % {
53             'scope': self.scope,
54             'ident': self.get_ident(request)
55         }
56 
57 
58 class TestView(APIView):
59     throttle_classes = [LuffyUserRateThrottle, LuffyAnonRateThrottle, ]
60 
61     def get(self, request, *args, **kwargs):
62         # self.dispatch
63         print(request.user)
64         print(request.auth)
65         return Response('GET请求,响应内容')
66 
67     def post(self, request, *args, **kwargs):
68         return Response('POST请求,响应内容')
69 
70     def put(self, request, *args, **kwargs):
71         return Response('PUT请求,响应内容')
views.py

5、全局使用

 1 REST_FRAMEWORK = {
 2     'DEFAULT_THROTTLE_CLASSES': [
 3         'api.utils.throttles.throttles.LuffyAnonRateThrottle',
 4         'api.utils.throttles.throttles.LuffyUserRateThrottle',
 5     ],
 6     'DEFAULT_THROTTLE_RATES': {
 7         'anon': '10/day',
 8         'user': '10/day',
 9         'luffy_anon': '10/m',
10         'luffy_user': '20/m',
11     },
12 }
settings.py

4.4版本

1、基于url的get传参方式

如:/users?version=v1

 

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

 

1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'^test/', TestView.as_view(),name='test'),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework.versioning import QueryParameterVersioning
 6 
 7 
 8 class TestView(APIView):
 9     versioning_class = QueryParameterVersioning
10 
11     def get(self, request, *args, **kwargs):
12 
13         # 获取版本
14         print(request.version)
15         # 获取版本管理的类
16         print(request.versioning_scheme)
17 
18         # 反向生成URL
19         reverse_url = request.versioning_scheme.reverse('test', request=request)
20         print(reverse_url)
21 
22         return Response('GET请求,响应内容')
23 
24     def post(self, request, *args, **kwargs):
25         return Response('POST请求,响应内容')
26 
27     def put(self, request, *args, **kwargs):
28         return Response('PUT请求,响应内容')
view.py

 

2、基于url的正则方式

如:/v1/users/

 

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

 

1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'^(?P<version>[v1|v2]+)/test/', TestView.as_view(), name='test'),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework.versioning import URLPathVersioning
 6 
 7 
 8 class TestView(APIView):
 9     versioning_class = URLPathVersioning
10 
11     def get(self, request, *args, **kwargs):
12         # 获取版本
13         print(request.version)
14         # 获取版本管理的类
15         print(request.versioning_scheme)
16 
17         # 反向生成URL
18         reverse_url = request.versioning_scheme.reverse('test', request=request)
19         print(reverse_url)
20 
21         return Response('GET请求,响应内容')
22 
23     def post(self, request, *args, **kwargs):
24         return Response('POST请求,响应内容')
25 
26     def put(self, request, *args, **kwargs):
27         return Response('PUT请求,响应内容')
views.py

 

 

3、基于 accept 请求头方式

 

如:Accept: application/json; version=1.0

1 REST_FRAMEWORK = {
2     'DEFAULT_VERSION': 'v1',            # 默认版本
3     'ALLOWED_VERSIONS': ['v1', 'v2'],   # 允许的版本
4     'VERSION_PARAM': 'version'          # URL中获取值的key
5 }
settings.py
1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'^test/', TestView.as_view(), name='test'),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework.versioning import AcceptHeaderVersioning
 6 
 7 
 8 class TestView(APIView):
 9     versioning_class = AcceptHeaderVersioning
10 
11     def get(self, request, *args, **kwargs):
12         # 获取版本 HTTP_ACCEPT头
13         print(request.version)
14         # 获取版本管理的类
15         print(request.versioning_scheme)
16         # 反向生成URL
17         reverse_url = request.versioning_scheme.reverse('test', request=request)
18         print(reverse_url)
19 
20         return Response('GET请求,响应内容')
21 
22     def post(self, request, *args, **kwargs):
23         return Response('POST请求,响应内容')
24 
25     def put(self, request, *args, **kwargs):
26         return Response('PUT请求,响应内容')
views.py

4、基于主机名方法

如:v1.example.com

1 ALLOWED_HOSTS = ['*']
2 REST_FRAMEWORK = {
3     'DEFAULT_VERSION': 'v1',  # 默认版本
4     'ALLOWED_VERSIONS': ['v1', 'v2'],  # 允许的版本
5     'VERSION_PARAM': 'version'  # URL中获取值的key
6 }
settings.py
1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'^test/', TestView.as_view(), name='test'),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework.versioning import HostNameVersioning
 6 
 7 
 8 class TestView(APIView):
 9     versioning_class = HostNameVersioning
10 
11     def get(self, request, *args, **kwargs):
12         # 获取版本
13         print(request.version)
14         # 获取版本管理的类
15         print(request.versioning_scheme)
16         # 反向生成URL
17         reverse_url = request.versioning_scheme.reverse('test', request=request)
18         print(reverse_url)
19 
20         return Response('GET请求,响应内容')
21 
22     def post(self, request, *args, **kwargs):
23         return Response('POST请求,响应内容')
24 
25     def put(self, request, *args, **kwargs):
26         return Response('PUT请求,响应内容')
views.py

5、基于django路由系统的namespace

如:example.com/v1/users/

1 REST_FRAMEWORK = {
2     'DEFAULT_VERSION': 'v1',  # 默认版本
3     'ALLOWED_VERSIONS': ['v1', 'v2'],  # 允许的版本
4     'VERSION_PARAM': 'version'  # URL中获取值的key
5 }
settings.py
 1 from django.conf.urls import url, include
 2 from web.views import TestView
 3 
 4 urlpatterns = [
 5     url(r'^v1/', ([
 6                       url(r'test/', TestView.as_view(), name='test'),
 7                   ], None, 'v1')),
 8     url(r'^v2/', ([
 9                       url(r'test/', TestView.as_view(), name='test'),
10                   ], None, 'v2')),
11 
12 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework.versioning import NamespaceVersioning
 6 
 7 
 8 class TestView(APIView):
 9     versioning_class = NamespaceVersioning
10 
11     def get(self, request, *args, **kwargs):
12         # 获取版本
13         print(request.version)
14         # 获取版本管理的类
15         print(request.versioning_scheme)
16         # 反向生成URL
17         reverse_url = request.versioning_scheme.reverse('test', request=request)
18         print(reverse_url)
19 
20         return Response('GET请求,响应内容')
21 
22     def post(self, request, *args, **kwargs):
23         return Response('POST请求,响应内容')
24 
25     def put(self, request, *args, **kwargs):
26         return Response('PUT请求,响应内容')
views.py

6、全局使用

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

4.5解释器(parser)

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

1、仅处理请求头content-type为application/json的请求体

1 from django.conf.urls import url, include
2 from web.views.s5_parser import TestView
3 
4 urlpatterns = [
5     url(r'test/', TestView.as_view(), name='test'),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework.request import Request
 6 from rest_framework.parsers import JSONParser
 7 
 8 
 9 class TestView(APIView):
10     parser_classes = [JSONParser, ]
11 
12     def post(self, request, *args, **kwargs):
13         print(request.content_type)
14 
15         # 获取请求的值,并使用对应的JSONParser进行处理
16         print(request.data)
17 
18         # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
19         print(request.POST)
20         print(request.FILES)
21 
22         return Response('POST请求,响应内容')
23 
24     def put(self, request, *args, **kwargs):
25         return Response('PUT请求,响应内容')
views.py

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

1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'test/', TestView.as_view(), name='test'),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework.request import Request
 6 from rest_framework.parsers import FormParser
 7 
 8 
 9 class TestView(APIView):
10     parser_classes = [FormParser, ]
11 
12     def post(self, request, *args, **kwargs):
13         print(request.content_type)
14 
15         # 获取请求的值,并使用对应的JSONParser进行处理
16         print(request.data)
17 
18         # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
19         print(request.POST)
20         print(request.FILES)
21 
22         return Response('POST请求,响应内容')
23 
24     def put(self, request, *args, **kwargs):
25         return Response('PUT请求,响应内容')
views.py

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

1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'test/', TestView.as_view(), name='test'),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework.request import Request
 6 from rest_framework.parsers import MultiPartParser
 7 
 8 
 9 class TestView(APIView):
10     parser_classes = [MultiPartParser, ]
11 
12     def post(self, request, *args, **kwargs):
13         print(request.content_type)
14 
15         # 获取请求的值,并使用对应的JSONParser进行处理
16         print(request.data)
17         # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
18         print(request.POST)
19         print(request.FILES)
20         return Response('POST请求,响应内容')
21 
22     def put(self, request, *args, **kwargs):
23         return Response('PUT请求,响应内容')
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.py

4、仅上传文件

1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'test/(?P<filename>[^/]+)', TestView.as_view(), name='test'),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework.request import Request
 6 from rest_framework.parsers import FileUploadParser
 7 
 8 
 9 class TestView(APIView):
10     parser_classes = [FileUploadParser, ]
11 
12     def post(self, request, filename, *args, **kwargs):
13         print(filename)
14         print(request.content_type)
15 
16         # 获取请求的值,并使用对应的JSONParser进行处理
17         print(request.data)
18         # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
19         print(request.POST)
20         print(request.FILES)
21         return Response('POST请求,响应内容')
22 
23     def put(self, request, *args, **kwargs):
24         return Response('PUT请求,响应内容')
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>
17 复制代码
upload.py

5、同时多个Parser

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

1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'test/', TestView.as_view(), name='test'),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework.request import Request
 6 from rest_framework.parsers import JSONParser, FormParser, MultiPartParser
 7 
 8 
 9 class TestView(APIView):
10     parser_classes = [JSONParser, FormParser, MultiPartParser, ]
11 
12     def post(self, request, *args, **kwargs):
13         print(request.content_type)
14 
15         # 获取请求的值,并使用对应的JSONParser进行处理
16         print(request.data)
17         # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
18         print(request.POST)
19         print(request.FILES)
20         return Response('POST请求,响应内容')
21 
22     def put(self, request, *args, **kwargs):
23         return Response('PUT请求,响应内容')
views.py

6、全局使用

1 REST_FRAMEWORK = {
2     'DEFAULT_PARSER_CLASSES':[
3         'rest_framework.parsers.JSONParser'
4         'rest_framework.parsers.FormParser'
5         'rest_framework.parsers.MultiPartParser'
6     ]
7 
8 }
settings.py
1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'test/', TestView.as_view(), name='test'),
6 ]
urls.py
 1 from rest_framework.views import APIView
 2 from rest_framework.response import Response
 3 
 4 
 5 class TestView(APIView):
 6     def post(self, request, *args, **kwargs):
 7         print(request.content_type)
 8 
 9         # 获取请求的值,并使用对应的JSONParser进行处理
10         print(request.data)
11         # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
12         print(request.POST)
13         print(request.FILES)
14         return Response('POST请求,响应内容')
15 
16     def put(self, request, *args, **kwargs):
17         return Response('PUT请求,响应内容')
views.py

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

4.6序列化

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

1、自定义字段

1 from django.conf.urls import url, include
2 from web.views.s6_serializers import TestView
3 
4 urlpatterns = [
5     url(r'test/', TestView.as_view(), name='test'),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework import serializers
 6 from .. import models
 7 
 8 
 9 class PasswordValidator(object):
10     def __init__(self, base):
11         self.base = base
12 
13     def __call__(self, value):
14         if value != self.base:
15             message = 'This field must be %s.' % self.base
16             raise serializers.ValidationError(message)
17 
18     def set_context(self, serializer_field):
19         """
20         This hook is called by the serializer instance,
21         prior to the validation call being made.
22         """
23         # 执行验证之前调用,serializer_fields是当前字段对象
24         pass
25 
26 
27 class UserSerializer(serializers.Serializer):
28     ut_title = serializers.CharField(source='ut.title')
29     user = serializers.CharField(min_length=6)
30     pwd = serializers.CharField(error_messages={'required': '密码不能为空'}, validators=[PasswordValidator('666')])
31 
32 
33 class TestView(APIView):
34     def get(self, request, *args, **kwargs):
35 
36         # 序列化,将数据库查询字段序列化为字典
37         data_list = models.UserInfo.objects.all()
38         ser = UserSerializer(instance=data_list, many=True)
39         #
40         # obj = models.UserInfo.objects.all().first()
41         # ser = UserSerializer(instance=obj, many=False)
42         return Response(ser.data)
43 
44     def post(self, request, *args, **kwargs):
45         # 验证,对请求发来的数据进行验证
46         ser = UserSerializer(data=request.data)
47         if ser.is_valid():
48             print(ser.validated_data)
49         else:
50             print(ser.errors)
51 
52         return Response('POST请求,响应内容')
views.py

2、基于Model自动生成字段

1 from django.conf.urls import url, include
2 from web.views.s6_serializers import TestView
3 
4 urlpatterns = [
5     url(r'test/', TestView.as_view(), name='test'),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework import serializers
 6 from .. import models
 7 
 8 
 9 class PasswordValidator(object):
10     def __init__(self, base):
11         self.base = str(base)
12 
13     def __call__(self, value):
14         if value != self.base:
15             message = 'This field must be %s.' % self.base
16             raise serializers.ValidationError(message)
17 
18     def set_context(self, serializer_field):
19         """
20         This hook is called by the serializer instance,
21         prior to the validation call being made.
22         """
23         # 执行验证之前调用,serializer_fields是当前字段对象
24         pass
25 
26 class ModelUserSerializer(serializers.ModelSerializer):
27 
28     user = serializers.CharField(max_length=32)
29 
30     class Meta:
31         model = models.UserInfo
32         fields = "__all__"
33         # fields = ['user', 'pwd', 'ut']
34         depth = 2
35         extra_kwargs = {'user': {'min_length': 6}, 'pwd': {'validators': [PasswordValidator(666), ]}}
36         # read_only_fields = ['user']
37 
38 
39 class TestView(APIView):
40     def get(self, request, *args, **kwargs):
41 
42         # 序列化,将数据库查询字段序列化为字典
43         data_list = models.UserInfo.objects.all()
44         ser = ModelUserSerializer(instance=data_list, many=True)
45         #
46         # obj = models.UserInfo.objects.all().first()
47         # ser = UserSerializer(instance=obj, many=False)
48         return Response(ser.data)
49 
50     def post(self, request, *args, **kwargs):
51         # 验证,对请求发来的数据进行验证
52         print(request.data)
53         ser = ModelUserSerializer(data=request.data)
54         if ser.is_valid():
55             print(ser.validated_data)
56         else:
57             print(ser.errors)
58 
59         return Response('POST请求,响应内容')
views.py

3、生成URL

1 from django.conf.urls import url, include
2 from web.views.s6_serializers import TestView
3 
4 urlpatterns = [
5     url(r'test/', TestView.as_view(), name='test'),
6     url(r'detail/(?P<pk>\d+)/', TestView.as_view(), name='detail'),
7 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework import serializers
 6 from .. import models
 7 
 8 
 9 class PasswordValidator(object):
10     def __init__(self, base):
11         self.base = str(base)
12 
13     def __call__(self, value):
14         if value != self.base:
15             message = 'This field must be %s.' % self.base
16             raise serializers.ValidationError(message)
17 
18     def set_context(self, serializer_field):
19         """
20         This hook is called by the serializer instance,
21         prior to the validation call being made.
22         """
23         # 执行验证之前调用,serializer_fields是当前字段对象
24         pass
25 
26 
27 class ModelUserSerializer(serializers.ModelSerializer):
28     ut = serializers.HyperlinkedIdentityField(view_name='detail')
29     class Meta:
30         model = models.UserInfo
31         fields = "__all__"
32 
33         extra_kwargs = {
34             'user': {'min_length': 6},
35             'pwd': {'validators': [PasswordValidator(666),]},
36         }
37 
38 
39 
40 class TestView(APIView):
41     def get(self, request, *args, **kwargs):
42 
43         # 序列化,将数据库查询字段序列化为字典
44         data_list = models.UserInfo.objects.all()
45         ser = ModelUserSerializer(instance=data_list, many=True, context={'request': request})
46         #
47         # obj = models.UserInfo.objects.all().first()
48         # ser = UserSerializer(instance=obj, many=False)
49         return Response(ser.data)
50 
51     def post(self, request, *args, **kwargs):
52         # 验证,对请求发来的数据进行验证
53         print(request.data)
54         ser = ModelUserSerializer(data=request.data)
55         if ser.is_valid():
56             print(ser.validated_data)
57         else:
58             print(ser.errors)
59 
60         return Response('POST请求,响应内容')
views.py

4、自动生成URL

1 from django.conf.urls import url, include
2 from web.views.s6_serializers import TestView
3 
4 urlpatterns = [
5     url(r'test/', TestView.as_view(), name='test'),
6     url(r'detail/(?P<pk>\d+)/', TestView.as_view(), name='xxxx'),
7 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework import serializers
 6 from .. import models
 7 
 8 
 9 class PasswordValidator(object):
10     def __init__(self, base):
11         self.base = str(base)
12 
13     def __call__(self, value):
14         if value != self.base:
15             message = 'This field must be %s.' % self.base
16             raise serializers.ValidationError(message)
17 
18     def set_context(self, serializer_field):
19         """
20         This hook is called by the serializer instance,
21         prior to the validation call being made.
22         """
23         # 执行验证之前调用,serializer_fields是当前字段对象
24         pass
25 
26 
27 class ModelUserSerializer(serializers.HyperlinkedModelSerializer):
28     ll = serializers.HyperlinkedIdentityField(view_name='xxxx')
29     tt = serializers.CharField(required=False)
30 
31     class Meta:
32         model = models.UserInfo
33         fields = "__all__"
34         list_serializer_class = serializers.ListSerializer
35 
36         extra_kwargs = {
37             'user': {'min_length': 6},
38             'pwd': {'validators': [PasswordValidator(666), ]},
39             'url': {'view_name': 'xxxx'},
40             'ut': {'view_name': 'xxxx'},
41         }
42 
43 
44 class TestView(APIView):
45     def get(self, request, *args, **kwargs):
46         # # 序列化,将数据库查询字段序列化为字典
47         data_list = models.UserInfo.objects.all()
48         ser = ModelUserSerializer(instance=data_list, many=True, context={'request': request})
49         # # 如果Many=True
50         # # 或
51         # # obj = models.UserInfo.objects.all().first()
52         # # ser = UserSerializer(instance=obj, many=False)
53         return Response(ser.data)
54 
55     def post(self, request, *args, **kwargs):
56         # 验证,对请求发来的数据进行验证
57         print(request.data)
58         ser = ModelUserSerializer(data=request.data)
59         if ser.is_valid():
60             print(ser.validated_data)
61         else:
62             print(ser.errors)
63 
64         return Response('POST请求,响应内容')
views.py

4.7分页

1、根据页码进行分页

1 from django.conf.urls import url, include
2 from rest_framework import routers
3 from web.views import s9_pagination
4 
5 urlpatterns = [
6     url(r'^test/', s9_pagination.UserViewSet.as_view()),
7 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework import serializers
 5 from .. import models
 6 
 7 from rest_framework.pagination import PageNumberPagination
 8 
 9 
10 class StandardResultsSetPagination(PageNumberPagination):
11     # 默认每页显示的数据条数
12     page_size = 1
13     # 获取URL参数中设置的每页显示数据条数
14     page_size_query_param = 'page_size'
15 
16     # 获取URL参数中传入的页码key
17     page_query_param = 'page'
18 
19     # 最大支持的每页显示的数据条数
20     max_page_size = 1
21 
22 
23 class UserSerializer(serializers.ModelSerializer):
24     class Meta:
25         model = models.UserInfo
26         fields = "__all__"
27 
28 
29 class UserViewSet(APIView):
30     def get(self, request, *args, **kwargs):
31         user_list = models.UserInfo.objects.all().order_by('-id')
32 
33         # 实例化分页对象,获取数据库中的分页数据
34         paginator = StandardResultsSetPagination()
35         page_user_list = paginator.paginate_queryset(user_list, self.request, view=self)
36 
37         # 序列化对象
38         serializer = UserSerializer(page_user_list, many=True)
39 
40         # 生成分页和数据
41         response = paginator.get_paginated_response(serializer.data)
42         return response
views.py

2、位置和个数进行分页

1 from django.conf.urls import url, include
2 from web.views import s9_pagination
3 
4 urlpatterns = [
5     url(r'^test/', s9_pagination.UserViewSet.as_view()),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework import serializers
 5 from .. import models
 6 
 7 from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination
 8 
 9 
10 class StandardResultsSetPagination(LimitOffsetPagination):
11     # 默认每页显示的数据条数
12     default_limit = 10
13     # URL中传入的显示数据条数的参数
14     limit_query_param = 'limit'
15     # URL中传入的数据位置的参数
16     offset_query_param = 'offset'
17     # 最大每页显得条数
18     max_limit = None
19 
20 class UserSerializer(serializers.ModelSerializer):
21     class Meta:
22         model = models.UserInfo
23         fields = "__all__"
24 
25 
26 class UserViewSet(APIView):
27     def get(self, request, *args, **kwargs):
28         user_list = models.UserInfo.objects.all().order_by('-id')
29 
30         # 实例化分页对象,获取数据库中的分页数据
31         paginator = StandardResultsSetPagination()
32         page_user_list = paginator.paginate_queryset(user_list, self.request, view=self)
33 
34         # 序列化对象
35         serializer = UserSerializer(page_user_list, many=True)
36 
37         # 生成分页和数据
38         response = paginator.get_paginated_response(serializer.data)
39         return response
views.py

3、游标分页

1 from django.conf.urls import url, include
2 from web.views import s9_pagination
3 
4 urlpatterns = [
5     url(r'^test/', s9_pagination.UserViewSet.as_view()),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework import serializers
 5 from .. import models
 6 
 7 from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
 8 
 9 
10 class StandardResultsSetPagination(CursorPagination):
11     # URL传入的游标参数
12     cursor_query_param = 'cursor'
13     # 默认每页显示的数据条数
14     page_size = 2
15     # URL传入的每页显示条数的参数
16     page_size_query_param = 'page_size'
17     # 每页显示数据最大条数
18     max_page_size = 1000
19 
20     # 根据ID从大到小排列
21     ordering = "id"
22 
23 
24 
25 class UserSerializer(serializers.ModelSerializer):
26     class Meta:
27         model = models.UserInfo
28         fields = "__all__"
29 
30 
31 class UserViewSet(APIView):
32     def get(self, request, *args, **kwargs):
33         user_list = models.UserInfo.objects.all().order_by('-id')
34 
35         # 实例化分页对象,获取数据库中的分页数据
36         paginator = StandardResultsSetPagination()
37         page_user_list = paginator.paginate_queryset(user_list, self.request, view=self)
38 
39         # 序列化对象
40         serializer = UserSerializer(page_user_list, many=True)
41 
42         # 生成分页和数据
43         response = paginator.get_paginated_response(serializer.data)
44         return response
views.py

4.8路由系统

1、自定义路由

1 from django.conf.urls import url, include
2 from web.views import s11_render
3 
4 urlpatterns = [
5     url(r'^test/$', s11_render.TestView.as_view()),
6     url(r'^test\.(?P<format>[a-z0-9]+)$', s11_render.TestView.as_view()),
7     url(r'^test/(?P<pk>[^/.]+)/$', s11_render.TestView.as_view()),
8     url(r'^test/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)$', s11_render.TestView.as_view())
9 ]
urls.py
 1 from rest_framework.views import APIView
 2 from rest_framework.response import Response
 3 from .. import models
 4 
 5 
 6 class TestView(APIView):
 7     def get(self, request, *args, **kwargs):
 8         print(kwargs)
 9         print(self.renderer_classes)
10         return Response('...')
views.py

2、半自动路由

1 from django.conf.urls import url, include
2 from web.views import s10_generic
3 
4 urlpatterns = [
5     url(r'^test/$', s10_generic.UserViewSet.as_view({'get': 'list', 'post': 'create'})),
6     url(r'^test/(?P<pk>\d+)/$', s10_generic.UserViewSet.as_view(
7         {'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'})),
8 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.viewsets import ModelViewSet
 4 from rest_framework import serializers
 5 from .. import models
 6 
 7 
 8 class UserSerializer(serializers.ModelSerializer):
 9     class Meta:
10         model = models.UserInfo
11         fields = "__all__"
12 
13 
14 class UserViewSet(ModelViewSet):
15     queryset = models.UserInfo.objects.all()
16     serializer_class = UserSerializer
views.py

3、全自动路由

 1 from django.conf.urls import url, include
 2 from rest_framework import routers
 3 from web.views import s10_generic
 4 
 5 
 6 router = routers.DefaultRouter()
 7 router.register(r'users', s10_generic.UserViewSet)
 8 
 9 urlpatterns = [
10     url(r'^', include(router.urls)),
11 ]
urls.py
 1 from rest_framework.viewsets import ModelViewSet
 2 from rest_framework import serializers
 3 from .. import models
 4 
 5 
 6 class UserSerializer(serializers.ModelSerializer):
 7     class Meta:
 8         model = models.UserInfo
 9         fields = "__all__"
10 
11 
12 class UserViewSet(ModelViewSet):
13     queryset = models.UserInfo.objects.all()
14     serializer_class = UserSerializer
views.py

 

4.9视图

1、GenericViewSet

1 from django.conf.urls import url, include
2 from web.views.s7_viewset import TestView
3 
4 urlpatterns = [
5     url(r'test/', TestView.as_view({'get':'list'}), name='test'),
6     url(r'detail/(?P<pk>\d+)/', TestView.as_view({'get':'list'}), name='xxxx'),
7 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework import viewsets
 4 from rest_framework.response import Response
 5 
 6 
 7 class TestView(viewsets.GenericViewSet):
 8     def list(self, request, *args, **kwargs):
 9         return Response('...')
10 
11     def add(self, request, *args, **kwargs):
12         pass
13 
14     def delete(self, request, *args, **kwargs):
15         pass
16 
17     def edit(self, request, *args, **kwargs):
18         pass
views.py

2、ModelViewSet(自定义URL)

1 from django.conf.urls import url, include
2 from web.views import s10_generic
3 
4 urlpatterns = [
5     url(r'^test/$', s10_generic.UserViewSet.as_view({'get': 'list', 'post': 'create'})),
6     url(r'^test/(?P<pk>\d+)/$', s10_generic.UserViewSet.as_view(
7         {'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'})),
8 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.viewsets import ModelViewSet
 4 from rest_framework import serializers
 5 from .. import models
 6 
 7 
 8 class UserSerializer(serializers.ModelSerializer):
 9     class Meta:
10         model = models.UserInfo
11         fields = "__all__"
12 
13 
14 class UserViewSet(ModelViewSet):
15     queryset = models.UserInfo.objects.all()
16     serializer_class = UserSerializer
views.py

3、ModelViewSet(rest framework路由)

 1 from django.conf.urls import url, include
 2 from rest_framework import routers
 3 from app01 import views
 4 
 5 router = routers.DefaultRouter()
 6 router.register(r'users', views.UserViewSet)
 7 router.register(r'groups', views.GroupViewSet)
 8 
 9 # Wire up our API using automatic URL routing.
10 # Additionally, we include login URLs for the browsable API.
11 urlpatterns = [
12     url(r'^', include(router.urls)),
13 ]
urls.py
 1 from rest_framework import viewsets
 2 from rest_framework import serializers
 3 
 4 
 5 class UserSerializer(serializers.HyperlinkedModelSerializer):
 6     class Meta:
 7         model = models.User
 8         fields = ('url', 'username', 'email', 'groups')
 9 
10 
11 class GroupSerializer(serializers.HyperlinkedModelSerializer):
12     class Meta:
13         model = models.Group
14         fields = ('url', 'name')
15         
16 class UserViewSet(viewsets.ModelViewSet):
17     """
18     API endpoint that allows users to be viewed or edited.
19     """
20     queryset = User.objects.all().order_by('-date_joined')
21     serializer_class = UserSerializer
22 
23 
24 class GroupViewSet(viewsets.ModelViewSet):
25     """
26     API endpoint that allows groups to be viewed or edited.
27     """
28     queryset = Group.objects.all()
29     serializer_class = GroupSerializer
views.py

4.10渲染器

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

  • http://127.0.0.1:8000/test/?format=json
  • http://127.0.0.1:8000/test.json

用户请求头:

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

1、json

访问URL:

    • http://127.0.0.1:8000/test/?format=json
    • http://127.0.0.1:8000/test.json
    • http://127.0.0.1:8000/test/ 
1 from django.conf.urls import url, include
2 from web.views import s11_render
3 
4 urlpatterns = [
5     url(r'^test/$', s11_render.TestView.as_view()),
6     url(r'^test\.(?P<format>[a-z0-9]+)', s11_render.TestView.as_view()),
7 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework import serializers
 6 
 7 from rest_framework.renderers import JSONRenderer
 8 
 9 from .. import models
10 
11 
12 class TestSerializer(serializers.ModelSerializer):
13     class Meta:
14         model = models.UserInfo
15         fields = "__all__"
16 
17 
18 class TestView(APIView):
19     renderer_classes = [JSONRenderer, ]
20 
21     def get(self, request, *args, **kwargs):
22         user_list = models.UserInfo.objects.all()
23         ser = TestSerializer(instance=user_list, many=True)
24         return Response(ser.data)
views.py

2、 表格

访问URL:

  • http://127.0.0.1:8000/test/?format=admin
  • http://127.0.0.1:8000/test.admin
  • http://127.0.0.1:8000/test/ 
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework import serializers
 6 
 7 from rest_framework.renderers import AdminRenderer
 8 
 9 from .. import models
10 
11 
12 class TestSerializer(serializers.ModelSerializer):
13     class Meta:
14         model = models.UserInfo
15         fields = "__all__"
16 
17 
18 class TestView(APIView):
19     renderer_classes = [AdminRenderer, ]
20 
21     def get(self, request, *args, **kwargs):
22         user_list = models.UserInfo.objects.all()
23         ser = TestSerializer(instance=user_list, many=True)
24         return Response(ser.data)
views.py

3、 Form表单

访问URL:

  • http://127.0.0.1:8000/test/?format=form
  • http://127.0.0.1:8000/test.form
  • http://127.0.0.1:8000/test/ 
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework import serializers
 6 
 7 from rest_framework.renderers import JSONRenderer
 8 from rest_framework.renderers import AdminRenderer
 9 from rest_framework.renderers import HTMLFormRenderer
10 
11 from .. import models
12 
13 
14 class TestSerializer(serializers.ModelSerializer):
15     class Meta:
16         model = models.UserInfo
17         fields = "__all__"
18 
19 
20 class TestView(APIView):
21     renderer_classes = [HTMLFormRenderer, ]
22 
23     def get(self, request, *args, **kwargs):
24         user_list = models.UserInfo.objects.all().first()
25         ser = TestSerializer(instance=user_list, many=False)
26         return Response(ser.data)
views.py

4、自定义显示模板

访问URL:

  • http://127.0.0.1:8000/test/?format=html
  • http://127.0.0.1:8000/test.html
  • http://127.0.0.1:8000/test/ 
1 from django.conf.urls import url, include
2 from web.views import s11_render
3 
4 urlpatterns = [
5     url(r'^test/$', s11_render.TestView.as_view()),
6     url(r'^test\.(?P<format>[a-z0-9]+)', s11_render.TestView.as_view()),
7 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework import serializers
 6 from rest_framework.renderers import TemplateHTMLRenderer
 7 
 8 from .. import models
 9 
10 
11 class TestSerializer(serializers.ModelSerializer):
12     class Meta:
13         model = models.UserInfo
14         fields = "__all__"
15 
16 
17 class TestView(APIView):
18     renderer_classes = [TemplateHTMLRenderer, ]
19 
20     def get(self, request, *args, **kwargs):
21         user_list = models.UserInfo.objects.all().first()
22         ser = TestSerializer(instance=user_list, many=False)
23         return Response(ser.data, template_name='user_detail.html')
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

 

5、 浏览器格式API+JSON

访问URL:

  • http://127.0.0.1:8000/test/?format=api
  • http://127.0.0.1:8000/test.api
  • http://127.0.0.1:8000/test/ 
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework import serializers
 6 
 7 from rest_framework.renderers import JSONRenderer
 8 from rest_framework.renderers import BrowsableAPIRenderer
 9 
10 from .. import models
11 
12 
13 class TestSerializer(serializers.ModelSerializer):
14     class Meta:
15         model = models.UserInfo
16         fields = "__all__"
17 
18 
19 class CustomBrowsableAPIRenderer(BrowsableAPIRenderer):
20     def get_default_renderer(self, view):
21         return JSONRenderer()
22 
23 
24 class TestView(APIView):
25     renderer_classes = [CustomBrowsableAPIRenderer, ]
26 
27     def get(self, request, *args, **kwargs):
28         user_list = models.UserInfo.objects.all().first()
29         ser = TestSerializer(instance=user_list, many=False)
30         return Response(ser.data, template_name='user_detail.html')
View Code

 

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

posted @ 2018-05-28 17:37  shuyang  阅读(399)  评论(0编辑  收藏  举报