一、什么是RESTful

REST与技术无关,代表一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”。

REST从资源的角度审视整个网络,它将分布在网络中某个节点的资源通过URL进行标识,客户端应用通过URL来获取资源的表征,获取这些表征致使这些应用转变状态。

所有的数据,不管是通过网络获取的还是操作(增删改查)的数据都是资源,将一切数据视为资源是REST区别于其他架构风格的最本质属性。

对于REST这种面向资源的架构风格,有人提出一种全新的结构理念,即面向资源架构(ROA:Resource Oriented Architecture)。

二、RESTful API设计

1.API与用户的通信协议,总是使用HTTPS协议。

2.域名

  • https://api.example.com  尽量将API部署在专用域名(会存在跨域问题)
  • https://example.org  API很简单

3.路径,视网络上任何东西都是资源,均使用名词表示(可复数)

  • https://api.example.com/v1/zoos
  • https://api.example.com/v1/animals

4.method

  • GET  从服务器取资源(一项或多项)
  • POST  在服务器新建一个资源
  • PUT  在服务器更新资源(客户端提供改变后的完整资源)
  • PATCH  在服务器更新资源(客户端提供改变的属性)
  • DELETE  从服务器删除资源

5.过滤,通过在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:指定筛选条件

6.状态码

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

常用状态码列表

7.错误处理,状态码是4XX时,应返回错误信息,error当作key

{error: "Invalid API key"
}

View Code

8.返回结果,针对不同操作,服务器向用户返回的结果应该符合以下规范。

GET /collection:返回资源对象的列表(数组)
GET /collection/resource:返回单个资源对象
POST /collection:返回新生成的资源对象
PUT /collection/resource:返回完整的资源对象
PATCH /collection/resource:返回完整的资源对象
DELETE /collection/resource:返回一个空文档

View Code

9.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"
}}

View Code

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

三、基于Django实现

路由系统:

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

View Code

CBV视图:

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

View Code

四、基于Django Rest framework框架实现

1.基本流程

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

url.py

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

views.py

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

2.认证和授权

(1)用户url传入的token认证

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

urls.py

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import BaseAuthentication
from rest_framework.request import Request
from rest_framework import exceptionstoken_list = ['sfsfss123kuf3j123','asijnfowerkkf9812',
]class TestAuthentication(BaseAuthentication):def authenticate(self, request):"""用户认证,如果验证成功后返回元组: (用户,用户Token):param request: :return: None,表示跳过该验证;如果跳过了所有认证,默认用户和Token和使用配置文件进行设置self._authenticator = Noneif api_settings.UNAUTHENTICATED_USER:self.user = api_settings.UNAUTHENTICATED_USER()else:self.user = Noneif api_settings.UNAUTHENTICATED_TOKEN:self.auth = api_settings.UNAUTHENTICATED_TOKEN()else:self.auth = None(user,token)表示验证通过并设置用户名和Token;AuthenticationFailed异常"""val = request.query_params.get('token')if val not in token_list:raise exceptions.AuthenticationFailed("用户认证失败")return ('登录用户', '用户token')def authenticate_header(self, request):"""Return a string to be used as the value of the `WWW-Authenticate`header in a `401 Unauthenticated` response, or `None` if theauthentication scheme should return `403 Permission Denied` responses."""# 验证失败时,返回的响应头WWW-Authenticate对应的值passclass TestView(APIView):authentication_classes = [TestAuthentication, ]permission_classes = []def get(self, request, *args, **kwargs):print(request.user)print(request.auth)return Response('GET请求,响应内容')def post(self, request, *args, **kwargs):return Response('POST请求,响应内容')def put(self, request, *args, **kwargs):return Response('PUT请求,响应内容')

views.py

(2)请求头认证

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

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import BaseAuthentication
from rest_framework.request import Request
from rest_framework import exceptionstoken_list = ['sfsfss123kuf3j123','asijnfowerkkf9812',
]class TestAuthentication(BaseAuthentication):def authenticate(self, request):"""用户认证,如果验证成功后返回元组: (用户,用户Token):param request: :return: None,表示跳过该验证;如果跳过了所有认证,默认用户和Token和使用配置文件进行设置self._authenticator = Noneif api_settings.UNAUTHENTICATED_USER:self.user = api_settings.UNAUTHENTICATED_USER()else:self.user = Noneif api_settings.UNAUTHENTICATED_TOKEN:self.auth = api_settings.UNAUTHENTICATED_TOKEN()else:self.auth = None(user,token)表示验证通过并设置用户名和Token;AuthenticationFailed异常"""import base64auth = request.META.get('HTTP_AUTHORIZATION', b'')if auth:auth = auth.encode('utf-8')auth = auth.split()if not auth or auth[0].lower() != b'basic':raise exceptions.AuthenticationFailed('验证失败')if len(auth) != 2:raise exceptions.AuthenticationFailed('验证失败')username, part, password = base64.b64decode(auth[1]).decode('utf-8').partition(':')if username == 'alex' and password == '123':return ('登录用户', '用户token')else:raise exceptions.AuthenticationFailed('用户名或密码错误')def authenticate_header(self, request):"""Return a string to be used as the value of the `WWW-Authenticate`header in a `401 Unauthenticated` response, or `None` if theauthentication scheme should return `403 Permission Denied` responses."""return 'Basic realm=api'class TestView(APIView):authentication_classes = [TestAuthentication, ]permission_classes = []def get(self, request, *args, **kwargs):print(request.user)print(request.auth)return Response('GET请求,响应内容')def post(self, request, *args, **kwargs):return Response('POST请求,响应内容')def put(self, request, *args, **kwargs):return Response('PUT请求,响应内容')

views.py

(3)多个认证规则

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

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import BaseAuthentication
from rest_framework.request import Request
from rest_framework import exceptionstoken_list = ['sfsfss123kuf3j123','asijnfowerkkf9812',
]class Test1Authentication(BaseAuthentication):def authenticate(self, request):"""用户认证,如果验证成功后返回元组: (用户,用户Token):param request: :return: None,表示跳过该验证;如果跳过了所有认证,默认用户和Token和使用配置文件进行设置self._authenticator = Noneif api_settings.UNAUTHENTICATED_USER:self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户else:self.user = Noneif api_settings.UNAUTHENTICATED_TOKEN:self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默认值为:Noneelse:self.auth = None(user,token)表示验证通过并设置用户名和Token;AuthenticationFailed异常"""import base64auth = request.META.get('HTTP_AUTHORIZATION', b'')if auth:auth = auth.encode('utf-8')else:return Noneprint(auth,'xxxx')auth = auth.split()if not auth or auth[0].lower() != b'basic':raise exceptions.AuthenticationFailed('验证失败')if len(auth) != 2:raise exceptions.AuthenticationFailed('验证失败')username, part, password = base64.b64decode(auth[1]).decode('utf-8').partition(':')if username == 'alex' and password == '123':return ('登录用户', '用户token')else:raise exceptions.AuthenticationFailed('用户名或密码错误')def authenticate_header(self, request):"""Return a string to be used as the value of the `WWW-Authenticate`header in a `401 Unauthenticated` response, or `None` if theauthentication scheme should return `403 Permission Denied` responses."""# return 'Basic realm=api'passclass Test2Authentication(BaseAuthentication):def authenticate(self, request):"""用户认证,如果验证成功后返回元组: (用户,用户Token):param request: :return: None,表示跳过该验证;如果跳过了所有认证,默认用户和Token和使用配置文件进行设置self._authenticator = Noneif api_settings.UNAUTHENTICATED_USER:self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户else:self.user = Noneif api_settings.UNAUTHENTICATED_TOKEN:self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默认值为:Noneelse:self.auth = None(user,token)表示验证通过并设置用户名和Token;AuthenticationFailed异常"""val = request.query_params.get('token')if val not in token_list:raise exceptions.AuthenticationFailed("用户认证失败")return ('登录用户', '用户token')def authenticate_header(self, request):"""Return a string to be used as the value of the `WWW-Authenticate`header in a `401 Unauthenticated` response, or `None` if theauthentication scheme should return `403 Permission Denied` responses."""passclass TestView(APIView):authentication_classes = [Test1Authentication, Test2Authentication]permission_classes = []def get(self, request, *args, **kwargs):print(request.user)print(request.auth)return Response('GET请求,响应内容')def post(self, request, *args, **kwargs):return Response('POST请求,响应内容')def put(self, request, *args, **kwargs):return Response('PUT请求,响应内容')

views.py

(4)认证和权限

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

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import BaseAuthentication
from rest_framework.permissions import BasePermissionfrom rest_framework.request import Request
from rest_framework import exceptionstoken_list = ['sfsfss123kuf3j123','asijnfowerkkf9812',
]class TestAuthentication(BaseAuthentication):def authenticate(self, request):"""用户认证,如果验证成功后返回元组: (用户,用户Token):param request: :return: None,表示跳过该验证;如果跳过了所有认证,默认用户和Token和使用配置文件进行设置self._authenticator = Noneif api_settings.UNAUTHENTICATED_USER:self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户else:self.user = Noneif api_settings.UNAUTHENTICATED_TOKEN:self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默认值为:Noneelse:self.auth = None(user,token)表示验证通过并设置用户名和Token;AuthenticationFailed异常"""val = request.query_params.get('token')if val not in token_list:raise exceptions.AuthenticationFailed("用户认证失败")return ('登录用户', '用户token')def authenticate_header(self, request):"""Return a string to be used as the value of the `WWW-Authenticate`header in a `401 Unauthenticated` response, or `None` if theauthentication scheme should return `403 Permission Denied` responses."""passclass TestPermission(BasePermission):message = "权限验证失败"def has_permission(self, request, view):"""判断是否有权限访问当前请求Return `True` if permission is granted, `False` otherwise.:param request: :param view: :return: True有权限;False无权限"""if request.user == "管理员":return True# GenericAPIView中get_object时调用def has_object_permission(self, request, view, obj):"""视图继承GenericAPIView,并在其中使用get_object时获取对象时,触发单独对象权限验证Return `True` if permission is granted, `False` otherwise.:param request: :param view: :param obj: :return: True有权限;False无权限"""if request.user == "管理员":return Trueclass TestView(APIView):# 认证的动作是由request.user触发authentication_classes = [TestAuthentication, ]# 权限# 循环执行所有的权限permission_classes = [TestPermission, ]def get(self, request, *args, **kwargs):# self.dispatchprint(request.user)print(request.auth)return Response('GET请求,响应内容')def post(self, request, *args, **kwargs):return Response('POST请求,响应内容')def put(self, request, *args, **kwargs):return Response('PUT请求,响应内容')

views.py

(5)全局使用

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

REST_FRAMEWORK = {'UNAUTHENTICATED_USER': None,'UNAUTHENTICATED_TOKEN': None,"DEFAULT_AUTHENTICATION_CLASSES": ["web.utils.TestAuthentication",],"DEFAULT_PERMISSION_CLASSES": ["web.utils.TestPermission",],
}

settings.py

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

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Responseclass TestView(APIView):def get(self, request, *args, **kwargs):# self.dispatchprint(request.user)print(request.auth)return Response('GET请求,响应内容')def post(self, request, *args, **kwargs):return Response('POST请求,响应内容')def put(self, request, *args, **kwargs):return Response('PUT请求,响应内容')

views.py

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

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

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

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import time
from rest_framework.views import APIView
from rest_framework.response import Responsefrom rest_framework import exceptions
from rest_framework.throttling import BaseThrottle
from rest_framework.settings import api_settings# 保存访问记录
RECORD = {'用户IP': [12312139, 12312135, 12312133, ]
}class TestThrottle(BaseThrottle):ctime = time.timedef get_ident(self, request):"""根据用户IP和代理IP,当做请求者的唯一IPIdentify the machine making the request by parsing HTTP_X_FORWARDED_FORif present and number of proxies is > 0. If not use all ofHTTP_X_FORWARDED_FOR if it is available, if not use REMOTE_ADDR."""xff = request.META.get('HTTP_X_FORWARDED_FOR')remote_addr = request.META.get('REMOTE_ADDR')num_proxies = api_settings.NUM_PROXIESif num_proxies is not None:if num_proxies == 0 or xff is None:return remote_addraddrs = xff.split(',')client_addr = addrs[-min(num_proxies, len(addrs))]return client_addr.strip()return ''.join(xff.split()) if xff else remote_addrdef allow_request(self, request, view):"""是否仍然在允许范围内Return `True` if the request should be allowed, `False` otherwise.:param request: :param view: :return: True,表示可以通过;False表示已超过限制,不允许访问"""# 获取用户唯一标识(如:IP)# 允许一分钟访问10次num_request = 10time_request = 60now = self.ctime()ident = self.get_ident(request)self.ident = identif ident not in RECORD:RECORD[ident] = [now, ]return Truehistory = RECORD[ident]while history and history[-1] <= now - time_request:history.pop()if len(history) < num_request:history.insert(0, now)return Truedef wait(self):"""多少秒后可以允许继续访问Optionally, return a recommended number of seconds to wait beforethe next request."""last_time = RECORD[self.ident][0]now = self.ctime()return int(60 + last_time - now)class TestView(APIView):throttle_classes = [TestThrottle, ]def get(self, request, *args, **kwargs):# self.dispatchprint(request.user)print(request.auth)return Response('GET请求,响应内容')def post(self, request, *args, **kwargs):return Response('POST请求,响应内容')def put(self, request, *args, **kwargs):return Response('PUT请求,响应内容')def throttled(self, request, wait):"""访问次数被限制时,定制错误信息"""class Throttled(exceptions.Throttled):default_detail = '请求被限制.'extra_detail_singular = '请 {wait} 秒之后再重试.'extra_detail_plural = '请 {wait} 秒之后再重试.'raise Throttled(wait)

views.py

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

REST_FRAMEWORK = {'DEFAULT_THROTTLE_RATES': {'test_scope': '10/m',},
}

settings.py

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

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Responsefrom rest_framework import exceptions
from rest_framework.throttling import SimpleRateThrottleclass TestThrottle(SimpleRateThrottle):# 配置文件定义的显示频率的Keyscope = "test_scope"def get_cache_key(self, request, view):"""Should return a unique cache-key which can be used for throttling.Must be overridden.May return `None` if the request should not be throttled."""if not request.user:ident = self.get_ident(request)else:ident = request.userreturn self.cache_format % {'scope': self.scope,'ident': ident}class TestView(APIView):throttle_classes = [TestThrottle, ]def get(self, request, *args, **kwargs):# self.dispatchprint(request.user)print(request.auth)return Response('GET请求,响应内容')def post(self, request, *args, **kwargs):return Response('POST请求,响应内容')def put(self, request, *args, **kwargs):return Response('PUT请求,响应内容')def throttled(self, request, wait):"""访问次数被限制时,定制错误信息"""class Throttled(exceptions.Throttled):default_detail = '请求被限制.'extra_detail_singular = '请 {wait} 秒之后再重试.'extra_detail_plural = '请 {wait} 秒之后再重试.'raise Throttled(wait)

views.py

(3)view中限制请求频率

REST_FRAMEWORK = {'DEFAULT_THROTTLE_RATES': {'xxxxxx': '10/m',},
}

settings.py

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

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Responsefrom rest_framework import exceptions
from rest_framework.throttling import ScopedRateThrottle# 继承 ScopedRateThrottle
class TestThrottle(ScopedRateThrottle):def get_cache_key(self, request, view):"""Should return a unique cache-key which can be used for throttling.Must be overridden.May return `None` if the request should not be throttled."""if not request.user:ident = self.get_ident(request)else:ident = request.userreturn self.cache_format % {'scope': self.scope,'ident': ident}class TestView(APIView):throttle_classes = [TestThrottle, ]# 在settings中获取 xxxxxx 对应的频率限制值throttle_scope = "xxxxxx"def get(self, request, *args, **kwargs):# self.dispatchprint(request.user)print(request.auth)return Response('GET请求,响应内容')def post(self, request, *args, **kwargs):return Response('POST请求,响应内容')def put(self, request, *args, **kwargs):return Response('PUT请求,响应内容')def throttled(self, request, wait):"""访问次数被限制时,定制错误信息"""class Throttled(exceptions.Throttled):default_detail = '请求被限制.'extra_detail_singular = '请 {wait} 秒之后再重试.'extra_detail_plural = '请 {wait} 秒之后再重试.'raise Throttled(wait)

views.py

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

REST_FRAMEWORK = {'UNAUTHENTICATED_USER': None,'UNAUTHENTICATED_TOKEN': None,'DEFAULT_THROTTLE_RATES': {'luffy_anon': '10/m','luffy_user': '20/m',},
}

settings.py

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

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Responsefrom rest_framework.throttling import SimpleRateThrottleclass LuffyAnonRateThrottle(SimpleRateThrottle):"""匿名用户,根据IP进行限制"""scope = "luffy_anon"def get_cache_key(self, request, view):# 用户已登录,则跳过 匿名频率限制if request.user:return Nonereturn self.cache_format % {'scope': self.scope,'ident': self.get_ident(request)}class LuffyUserRateThrottle(SimpleRateThrottle):"""登录用户,根据用户token限制"""scope = "luffy_user"def get_ident(self, request):"""认证成功时:request.user是用户对象;request.auth是token对象:param request: :return: """# return request.auth.tokenreturn "user_token"def get_cache_key(self, request, view):"""获取缓存key:param request: :param view: :return: """# 未登录用户,则跳过 Token限制if not request.user:return Nonereturn self.cache_format % {'scope': self.scope,'ident': self.get_ident(request)}class TestView(APIView):throttle_classes = [LuffyUserRateThrottle, LuffyAnonRateThrottle, ]def get(self, request, *args, **kwargs):# self.dispatchprint(request.user)print(request.auth)return Response('GET请求,响应内容')def post(self, request, *args, **kwargs):return Response('POST请求,响应内容')def put(self, request, *args, **kwargs):return Response('PUT请求,响应内容')

views.py

(5)全局使用

REST_FRAMEWORK = {'DEFAULT_THROTTLE_CLASSES': ['api.utils.throttles.throttles.LuffyAnonRateThrottle','api.utils.throttles.throttles.LuffyUserRateThrottle',],'DEFAULT_THROTTLE_RATES': {'anon': '10/day','user': '10/day','luffy_anon': '10/m','luffy_user': '20/m',},
}

settings

4.版本

(1)基于url的get传参方式

如:/users?version=v1

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

settings.py

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

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import QueryParameterVersioningclass TestView(APIView):versioning_class = QueryParameterVersioningdef get(self, request, *args, **kwargs):# 获取版本print(request.version)# 获取版本管理的类print(request.versioning_scheme)# 反向生成URLreverse_url = request.versioning_scheme.reverse('test', request=request)print(reverse_url)return Response('GET请求,响应内容')def post(self, request, *args, **kwargs):return Response('POST请求,响应内容')def put(self, request, *args, **kwargs):return Response('PUT请求,响应内容')

views.py

(2)基于url的正则方式

如:/v1/users/

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

settings.py

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

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import URLPathVersioningclass TestView(APIView):versioning_class = URLPathVersioningdef get(self, request, *args, **kwargs):# 获取版本print(request.version)# 获取版本管理的类print(request.versioning_scheme)# 反向生成URLreverse_url = request.versioning_scheme.reverse('test', request=request)print(reverse_url)return Response('GET请求,响应内容')def post(self, request, *args, **kwargs):return Response('POST请求,响应内容')def put(self, request, *args, **kwargs):return Response('PUT请求,响应内容')

views.py

(3)基于accept请求方式

如:Accept: application/json; version=1.0

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

settings.py

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

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import AcceptHeaderVersioningclass TestView(APIView):versioning_class = AcceptHeaderVersioningdef get(self, request, *args, **kwargs):# 获取版本 HTTP_ACCEPT头print(request.version)# 获取版本管理的类print(request.versioning_scheme)# 反向生成URLreverse_url = request.versioning_scheme.reverse('test', request=request)print(reverse_url)return Response('GET请求,响应内容')def post(self, request, *args, **kwargs):return Response('POST请求,响应内容')def put(self, request, *args, **kwargs):return Response('PUT请求,响应内容')

views.py

(4)基于主机名方法

如:v1.example.com

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

settings.py

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

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import HostNameVersioningclass TestView(APIView):versioning_class = HostNameVersioningdef get(self, request, *args, **kwargs):# 获取版本print(request.version)# 获取版本管理的类print(request.versioning_scheme)# 反向生成URLreverse_url = request.versioning_scheme.reverse('test', request=request)print(reverse_url)return Response('GET请求,响应内容')def post(self, request, *args, **kwargs):return Response('POST请求,响应内容')def put(self, request, *args, **kwargs):return Response('PUT请求,响应内容')

views.py

(5)基于Django路由系统的namespace

如:example.com/v1/users/

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

setting.py

from django.conf.urls import url, include
from web.views import TestViewurlpatterns = [url(r'^v1/', ([url(r'test/', TestView.as_view(), name='test'),], None, 'v1')),url(r'^v2/', ([url(r'test/', TestView.as_view(), name='test'),], None, 'v2')),]

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import NamespaceVersioningclass TestView(APIView):versioning_class = NamespaceVersioningdef get(self, request, *args, **kwargs):# 获取版本print(request.version)# 获取版本管理的类print(request.versioning_scheme)# 反向生成URLreverse_url = request.versioning_scheme.reverse('test', request=request)print(reverse_url)return Response('GET请求,响应内容')def post(self, request, *args, **kwargs):return Response('POST请求,响应内容')def put(self, request, *args, **kwargs):return Response('PUT请求,响应内容')

views.py

(6)全局使用

REST_FRAMEWORK = {'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning",'DEFAULT_VERSION': 'v1','ALLOWED_VERSIONS': ['v1', 'v2'],'VERSION_PARAM': 'version'
}

settings.py

5.解析器(parser)

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

(1)进处理请求头content-type为application/json的请求体

from django.conf.urls import url, include
from web.views.s5_parser import TestViewurlpatterns = [url(r'test/', TestView.as_view(), name='test'),
]

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import JSONParserclass TestView(APIView):parser_classes = [JSONParser, ]def post(self, request, *args, **kwargs):print(request.content_type)# 获取请求的值,并使用对应的JSONParser进行处理print(request.data)# application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值print(request.POST)print(request.FILES)return Response('POST请求,响应内容')def put(self, request, *args, **kwargs):return Response('PUT请求,响应内容')

views.py

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

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

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import FormParserclass TestView(APIView):parser_classes = [FormParser, ]def post(self, request, *args, **kwargs):print(request.content_type)# 获取请求的值,并使用对应的JSONParser进行处理print(request.data)# application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值print(request.POST)print(request.FILES)return Response('POST请求,响应内容')def put(self, request, *args, **kwargs):return Response('PUT请求,响应内容')

views.py

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

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

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import MultiPartParserclass TestView(APIView):parser_classes = [MultiPartParser, ]def post(self, request, *args, **kwargs):print(request.content_type)# 获取请求的值,并使用对应的JSONParser进行处理print(request.data)# application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值print(request.POST)print(request.FILES)return Response('POST请求,响应内容')def put(self, request, *args, **kwargs):return Response('PUT请求,响应内容')

views.py

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<form action="http://127.0.0.1:8000/test/" method="post" enctype="multipart/form-data"><input type="text" name="user" /><input type="file" name="img"><input type="submit" value="提交"></form>
</body>
</html>

upload.html

(4)仅上传文件

from django.conf.urls import url, include
from web.views import TestViewurlpatterns = [url(r'test/(?P<filename>[^/]+)', TestView.as_view(), name='test'),
]

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import FileUploadParserclass TestView(APIView):parser_classes = [FileUploadParser, ]def post(self, request, filename, *args, **kwargs):print(filename)print(request.content_type)# 获取请求的值,并使用对应的JSONParser进行处理print(request.data)# application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值print(request.POST)print(request.FILES)return Response('POST请求,响应内容')def put(self, request, *args, **kwargs):return Response('PUT请求,响应内容')

views.py

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<form action="http://127.0.0.1:8000/test/f1.numbers" method="post" enctype="multipart/form-data"><input type="text" name="user" /><input type="file" name="img"><input type="submit" value="提交"></form>
</body>
</html>

upload.html

(5)同时多个Parser

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

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

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import JSONParser, FormParser, MultiPartParserclass TestView(APIView):parser_classes = [JSONParser, FormParser, MultiPartParser, ]def post(self, request, *args, **kwargs):print(request.content_type)# 获取请求的值,并使用对应的JSONParser进行处理print(request.data)# application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值print(request.POST)print(request.FILES)return Response('POST请求,响应内容')def put(self, request, *args, **kwargs):return Response('PUT请求,响应内容')

views.py

(6)全局使用

REST_FRAMEWORK = {'DEFAULT_PARSER_CLASSES':['rest_framework.parsers.JSONParser''rest_framework.parsers.FormParser''rest_framework.parsers.MultiPartParser']}

settings.py

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

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Responseclass TestView(APIView):def post(self, request, *args, **kwargs):print(request.content_type)# 获取请求的值,并使用对应的JSONParser进行处理print(request.data)# application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值print(request.POST)print(request.FILES)return Response('POST请求,响应内容')def put(self, request, *args, **kwargs):return Response('PUT请求,响应内容')

views.py

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

6.序列化

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

(1)自定义字段

from django.conf.urls import url, include
from web.views.s6_serializers import TestViewurlpatterns = [url(r'test/', TestView.as_view(), name='test'),
]

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from .. import modelsclass PasswordValidator(object):def __init__(self, base):self.base = basedef __call__(self, value):if value != self.base:message = 'This field must be %s.' % self.baseraise serializers.ValidationError(message)def set_context(self, serializer_field):"""This hook is called by the serializer instance,prior to the validation call being made."""# 执行验证之前调用,serializer_fields是当前字段对象passclass UserSerializer(serializers.Serializer):ut_title = serializers.CharField(source='ut.title')user = serializers.CharField(min_length=6)pwd = serializers.CharField(error_messages={'required': '密码不能为空'}, validators=[PasswordValidator('666')])class TestView(APIView):def get(self, request, *args, **kwargs):# 序列化,将数据库查询字段序列化为字典data_list = models.UserInfo.objects.all()ser = UserSerializer(instance=data_list, many=True)# 或# obj = models.UserInfo.objects.all().first()# ser = UserSerializer(instance=obj, many=False)return Response(ser.data)def post(self, request, *args, **kwargs):# 验证,对请求发来的数据进行验证ser = UserSerializer(data=request.data)if ser.is_valid():print(ser.validated_data)else:print(ser.errors)return Response('POST请求,响应内容')

views.py

(2)基于Model自动生成字段

from django.conf.urls import url, include
from web.views.s6_serializers import TestViewurlpatterns = [url(r'test/', TestView.as_view(), name='test'),
]

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from .. import modelsclass PasswordValidator(object):def __init__(self, base):self.base = str(base)def __call__(self, value):if value != self.base:message = 'This field must be %s.' % self.baseraise serializers.ValidationError(message)def set_context(self, serializer_field):"""This hook is called by the serializer instance,prior to the validation call being made."""# 执行验证之前调用,serializer_fields是当前字段对象passclass ModelUserSerializer(serializers.ModelSerializer):user = serializers.CharField(max_length=32)class Meta:model = models.UserInfofields = "__all__"# fields = ['user', 'pwd', 'ut']depth = 2extra_kwargs = {'user': {'min_length': 6}, 'pwd': {'validators': [PasswordValidator(666), ]}}# read_only_fields = ['user']class TestView(APIView):def get(self, request, *args, **kwargs):# 序列化,将数据库查询字段序列化为字典data_list = models.UserInfo.objects.all()ser = ModelUserSerializer(instance=data_list, many=True)# 或# obj = models.UserInfo.objects.all().first()# ser = UserSerializer(instance=obj, many=False)return Response(ser.data)def post(self, request, *args, **kwargs):# 验证,对请求发来的数据进行验证print(request.data)ser = ModelUserSerializer(data=request.data)if ser.is_valid():print(ser.validated_data)else:print(ser.errors)return Response('POST请求,响应内容')

views.py

(3)生成URL

from django.conf.urls import url, include
from web.views.s6_serializers import TestViewurlpatterns = [url(r'test/', TestView.as_view(), name='test'),url(r'detail/(?P<pk>\d+)/', TestView.as_view(), name='detail'),
]

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from .. import modelsclass PasswordValidator(object):def __init__(self, base):self.base = str(base)def __call__(self, value):if value != self.base:message = 'This field must be %s.' % self.baseraise serializers.ValidationError(message)def set_context(self, serializer_field):"""This hook is called by the serializer instance,prior to the validation call being made."""# 执行验证之前调用,serializer_fields是当前字段对象passclass ModelUserSerializer(serializers.ModelSerializer):ut = serializers.HyperlinkedIdentityField(view_name='detail')class Meta:model = models.UserInfofields = "__all__"extra_kwargs = {'user': {'min_length': 6},'pwd': {'validators': [PasswordValidator(666),]},}class TestView(APIView):def get(self, request, *args, **kwargs):# 序列化,将数据库查询字段序列化为字典data_list = models.UserInfo.objects.all()ser = ModelUserSerializer(instance=data_list, many=True, context={'request': request})# 或# obj = models.UserInfo.objects.all().first()# ser = UserSerializer(instance=obj, many=False)return Response(ser.data)def post(self, request, *args, **kwargs):# 验证,对请求发来的数据进行验证print(request.data)ser = ModelUserSerializer(data=request.data)if ser.is_valid():print(ser.validated_data)else:print(ser.errors)return Response('POST请求,响应内容')

views.py

(4)自动生成URL

from django.conf.urls import url, include
from web.views.s6_serializers import TestViewurlpatterns = [url(r'test/', TestView.as_view(), name='test'),url(r'detail/(?P<pk>\d+)/', TestView.as_view(), name='xxxx'),
]

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from .. import modelsclass PasswordValidator(object):def __init__(self, base):self.base = str(base)def __call__(self, value):if value != self.base:message = 'This field must be %s.' % self.baseraise serializers.ValidationError(message)def set_context(self, serializer_field):"""This hook is called by the serializer instance,prior to the validation call being made."""# 执行验证之前调用,serializer_fields是当前字段对象passclass ModelUserSerializer(serializers.HyperlinkedModelSerializer):ll = serializers.HyperlinkedIdentityField(view_name='xxxx')tt = serializers.CharField(required=False)class Meta:model = models.UserInfofields = "__all__"list_serializer_class = serializers.ListSerializerextra_kwargs = {'user': {'min_length': 6},'pwd': {'validators': [PasswordValidator(666), ]},'url': {'view_name': 'xxxx'},'ut': {'view_name': 'xxxx'},}class TestView(APIView):def get(self, request, *args, **kwargs):# # 序列化,将数据库查询字段序列化为字典data_list = models.UserInfo.objects.all()ser = ModelUserSerializer(instance=data_list, many=True, context={'request': request})# # 如果Many=True# # 或# # obj = models.UserInfo.objects.all().first()# # ser = UserSerializer(instance=obj, many=False)return Response(ser.data)def post(self, request, *args, **kwargs):# 验证,对请求发来的数据进行验证print(request.data)ser = ModelUserSerializer(data=request.data)if ser.is_valid():print(ser.validated_data)else:print(ser.errors)return Response('POST请求,响应内容')

views.py

7.分页

(1)根据页码进行分页

from django.conf.urls import url, include
from rest_framework import routers
from web.views import s9_paginationurlpatterns = [url(r'^test/', s9_pagination.UserViewSet.as_view()),
]

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework import serializers
from .. import modelsfrom rest_framework.pagination import PageNumberPaginationclass StandardResultsSetPagination(PageNumberPagination):# 默认每页显示的数据条数page_size = 1# 获取URL参数中设置的每页显示数据条数page_size_query_param = 'page_size'# 获取URL参数中传入的页码keypage_query_param = 'page'# 最大支持的每页显示的数据条数max_page_size = 1class UserSerializer(serializers.ModelSerializer):class Meta:model = models.UserInfofields = "__all__"class UserViewSet(APIView):def get(self, request, *args, **kwargs):user_list = models.UserInfo.objects.all().order_by('-id')# 实例化分页对象,获取数据库中的分页数据paginator = StandardResultsSetPagination()page_user_list = paginator.paginate_queryset(user_list, self.request, view=self)# 序列化对象serializer = UserSerializer(page_user_list, many=True)# 生成分页和数据response = paginator.get_paginated_response(serializer.data)return response

views.py

(2)位置和个数进行分页

from django.conf.urls import url, include
from web.views import s9_paginationurlpatterns = [url(r'^test/', s9_pagination.UserViewSet.as_view()),
]

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework import serializers
from .. import modelsfrom rest_framework.pagination import PageNumberPagination,LimitOffsetPaginationclass StandardResultsSetPagination(LimitOffsetPagination):# 默认每页显示的数据条数default_limit = 10# URL中传入的显示数据条数的参数limit_query_param = 'limit'# URL中传入的数据位置的参数offset_query_param = 'offset'# 最大每页显得条数max_limit = Noneclass UserSerializer(serializers.ModelSerializer):class Meta:model = models.UserInfofields = "__all__"class UserViewSet(APIView):def get(self, request, *args, **kwargs):user_list = models.UserInfo.objects.all().order_by('-id')# 实例化分页对象,获取数据库中的分页数据paginator = StandardResultsSetPagination()page_user_list = paginator.paginate_queryset(user_list, self.request, view=self)# 序列化对象serializer = UserSerializer(page_user_list, many=True)# 生成分页和数据response = paginator.get_paginated_response(serializer.data)return response

views.py

(3)游标分页

from django.conf.urls import url, include
from web.views import s9_paginationurlpatterns = [url(r'^test/', s9_pagination.UserViewSet.as_view()),
]

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework import serializers
from .. import modelsfrom rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPaginationclass StandardResultsSetPagination(CursorPagination):# URL传入的游标参数cursor_query_param = 'cursor'# 默认每页显示的数据条数page_size = 2# URL传入的每页显示条数的参数page_size_query_param = 'page_size'# 每页显示数据最大条数max_page_size = 1000# 根据ID从大到小排列ordering = "id"class UserSerializer(serializers.ModelSerializer):class Meta:model = models.UserInfofields = "__all__"class UserViewSet(APIView):def get(self, request, *args, **kwargs):user_list = models.UserInfo.objects.all().order_by('-id')# 实例化分页对象,获取数据库中的分页数据paginator = StandardResultsSetPagination()page_user_list = paginator.paginate_queryset(user_list, self.request, view=self)# 序列化对象serializer = UserSerializer(page_user_list, many=True)# 生成分页和数据response = paginator.get_paginated_response(serializer.data)return response

views.py

8.路由系统

(1)自定义路由

from django.conf.urls import url, include
from web.views import s11_renderurlpatterns = [url(r'^test/$', s11_render.TestView.as_view()),url(r'^test\.(?P<format>[a-z0-9]+)$', s11_render.TestView.as_view()),url(r'^test/(?P<pk>[^/.]+)/$', s11_render.TestView.as_view()),url(r'^test/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)$', s11_render.TestView.as_view())
]

urls.py

from rest_framework.views import APIView
from rest_framework.response import Response
from .. import modelsclass TestView(APIView):def get(self, request, *args, **kwargs):print(kwargs)print(self.renderer_classes)return Response('...')

views.py

(2)半自动路由

from django.conf.urls import url, include
from web.views import s10_genericurlpatterns = [url(r'^test/$', s10_generic.UserViewSet.as_view({'get': 'list', 'post': 'create'})),url(r'^test/(?P<pk>\d+)/$', s10_generic.UserViewSet.as_view({'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'})),
]

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.viewsets import ModelViewSet
from rest_framework import serializers
from .. import modelsclass UserSerializer(serializers.ModelSerializer):class Meta:model = models.UserInfofields = "__all__"class UserViewSet(ModelViewSet):queryset = models.UserInfo.objects.all()serializer_class = UserSerializer

views.py

(3)全自动路由

from django.conf.urls import url, include
from rest_framework import routers
from web.views import s10_genericrouter = routers.DefaultRouter()
router.register(r'users', s10_generic.UserViewSet)urlpatterns = [url(r'^', include(router.urls)),
]

urls.py

from rest_framework.viewsets import ModelViewSet
from rest_framework import serializers
from .. import modelsclass UserSerializer(serializers.ModelSerializer):class Meta:model = models.UserInfofields = "__all__"class UserViewSet(ModelViewSet):queryset = models.UserInfo.objects.all()serializer_class = UserSerializer

views.py

9.视图

(1)GenericViewSet

from django.conf.urls import url, include
from web.views.s7_viewset import TestViewurlpatterns = [url(r'test/', TestView.as_view({'get':'list'}), name='test'),url(r'detail/(?P<pk>\d+)/', TestView.as_view({'get':'list'}), name='xxxx'),
]

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework import viewsets
from rest_framework.response import Responseclass TestView(viewsets.GenericViewSet):def list(self, request, *args, **kwargs):return Response('...')def add(self, request, *args, **kwargs):passdef delete(self, request, *args, **kwargs):passdef edit(self, request, *args, **kwargs):pass

views.py

(2)ModelViewSet(自定义URL)

from django.conf.urls import url, include
from web.views import s10_genericurlpatterns = [url(r'^test/$', s10_generic.UserViewSet.as_view({'get': 'list', 'post': 'create'})),url(r'^test/(?P<pk>\d+)/$', s10_generic.UserViewSet.as_view({'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'})),
]

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.viewsets import ModelViewSet
from rest_framework import serializers
from .. import modelsclass UserSerializer(serializers.ModelSerializer):class Meta:model = models.UserInfofields = "__all__"class UserViewSet(ModelViewSet):queryset = models.UserInfo.objects.all()serializer_class = UserSerializer

views.py

(3)ModelViewSet(rest framework路由)

from django.conf.urls import url, include
from rest_framework import routers
from app01 import viewsrouter = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'groups', views.GroupViewSet)# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API.
urlpatterns = [url(r'^', include(router.urls)),
]

urls.py

from rest_framework import viewsets
from rest_framework import serializersclass UserSerializer(serializers.HyperlinkedModelSerializer):class Meta:model = models.Userfields = ('url', 'username', 'email', 'groups')class GroupSerializer(serializers.HyperlinkedModelSerializer):class Meta:model = models.Groupfields = ('url', 'name')class UserViewSet(viewsets.ModelViewSet):"""API endpoint that allows users to be viewed or edited."""queryset = User.objects.all().order_by('-date_joined')serializer_class = UserSerializerclass GroupViewSet(viewsets.ModelViewSet):"""API endpoint that allows groups to be viewed or edited."""queryset = Group.objects.all()serializer_class = GroupSerializer

views.py

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/

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

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializersfrom rest_framework.renderers import JSONRendererfrom .. import modelsclass TestSerializer(serializers.ModelSerializer):class Meta:model = models.UserInfofields = "__all__"class TestView(APIView):renderer_classes = [JSONRenderer, ]def get(self, request, *args, **kwargs):user_list = models.UserInfo.objects.all()ser = TestSerializer(instance=user_list, many=True)return Response(ser.data)

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/

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializersfrom rest_framework.renderers import AdminRendererfrom .. import modelsclass TestSerializer(serializers.ModelSerializer):class Meta:model = models.UserInfofields = "__all__"class TestView(APIView):renderer_classes = [AdminRenderer, ]def get(self, request, *args, **kwargs):user_list = models.UserInfo.objects.all()ser = TestSerializer(instance=user_list, many=True)return Response(ser.data)

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/

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializersfrom rest_framework.renderers import JSONRenderer
from rest_framework.renderers import AdminRenderer
from rest_framework.renderers import HTMLFormRendererfrom .. import modelsclass TestSerializer(serializers.ModelSerializer):class Meta:model = models.UserInfofields = "__all__"class TestView(APIView):renderer_classes = [HTMLFormRenderer, ]def get(self, request, *args, **kwargs):user_list = models.UserInfo.objects.all().first()ser = TestSerializer(instance=user_list, many=False)return Response(ser.data)

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/

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

urls.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from rest_framework.renderers import TemplateHTMLRendererfrom .. import modelsclass TestSerializer(serializers.ModelSerializer):class Meta:model = models.UserInfofields = "__all__"class TestView(APIView):renderer_classes = [TemplateHTMLRenderer, ]def get(self, request, *args, **kwargs):user_list = models.UserInfo.objects.all().first()ser = TestSerializer(instance=user_list, many=False)return Response(ser.data, template_name='user_detail.html')

views.py

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>{{ user }}{{ pwd }}{{ ut }}
</body>
</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/

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializersfrom rest_framework.renderers import JSONRenderer
from rest_framework.renderers import BrowsableAPIRendererfrom .. import modelsclass TestSerializer(serializers.ModelSerializer):class Meta:model = models.UserInfofields = "__all__"class CustomBrowsableAPIRenderer(BrowsableAPIRenderer):def get_default_renderer(self, view):return JSONRenderer()class TestView(APIView):renderer_classes = [CustomBrowsableAPIRenderer, ]def get(self, request, *args, **kwargs):user_list = models.UserInfo.objects.all().first()ser = TestSerializer(instance=user_list, many=False)return Response(ser.data, template_name='user_detail.html')

views.py

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

转载于:https://www.cnblogs.com/yangmingxianshen/p/8847178.html

Django Rest Framework(一)相关推荐

  1. 03 Django REST Framework 视图和路由

    01-DRF中的request 在Django REST Framework中内置的Request类扩展了Django中的Request类,实现了很多方便的功能--如请求数据解析和认证等. 比如,区别 ...

  2. Django REST framework 简介

    1.在序列化与反序列化时,虽然操作的数据不尽相同,但是执行的过程却是相似的,也就是说这部分代码是可以复用简化编写的. 2.在开发REST API的视图中,虽然每个视图具体操作的数据不同,但增.删.改. ...

  3. Django REST framework API 指南(2):响应

    Django REST framework API 指南(1):请求 Django REST framework API 指南(2):响应 Django REST framework API 指南(3 ...

  4. Django REST framework API 指南(12):验证器

    官方原文链接 本系列文章 github 地址 转载请注明出处 验证器 大多数情况下,您在 REST framework 中处理验证时,只需依赖默认的字段验证,或者在序列化类或字段类上编写明确的验证方法 ...

  5. Django REST framework的一些奇巧淫技(干货!!!)

    开始之前,假设你已经有Django和Django REST framework的一些基础了 mixins,ViewSet和routers配合使用 minxis的类有5种 CreateModelMixi ...

  6. Django REST framework快速入门

    1)简介: 接口使用REST framework,REST framework是一套基于Django 的 REST 框架,是一个强大灵活的构建 Web API 的工具包. 写接口三步完成:连接数据库. ...

  7. Django REST framework 1

    Django REST framework Django REST framework官方文档:点击  中文文档:点击 安装djangorestframework:pip3 install djang ...

  8. Django REST framework的各种技巧——1.基础讲解

    写在最上面的话 django是一个神奇的框架,而restframework又是遵循了这个框架的另一个神奇的框架,然而由于restframework的文档稀烂无比,很多时候你必须看源码才能写出科学的代码 ...

  9. 在django restful framework中设置django model的property

    众所周知,在django的model中,可以某些字段设置@property和setter deleter getter,这样就可以在存入数据的时候进行一些操作,具体原理请参见廖雪峰大神的博客https ...

  10. Django Rest Framework

    新的一年启程,大家又投入到紧张的学习和工作中,作为一个互联网人必须时刻紧跟科技发展的脚步.对于大火的 Python 编程语言我们怎么能错过,我们[51Reboot]这就为大家带来新年的第一堂 Pyth ...

最新文章

  1. Lidar激光雷达市场
  2. Android studio中2种build.gradle文件介绍
  3. Lucene4.3.1 拼写检查SpellChecker
  4. H - Hello Ms. Ze(树状数组套主席树,线段树上二分)
  5. caffe:制作自己的数据集train.txt和val.txt,生成lmdb文件
  6. Python 根据图片url,批量下载图片
  7. android与单片机wifi通信原理图,单片机怎么和wifi模块实现通讯_wifi模块与单片机通信原理 - 全文...
  8. 洛谷 P1873 [COCI 2011/2012 #5] EKO / 砍树
  9. 用python wxpy管理微信公众号,并利用微信获取自己的开源数据。
  10. 将PSD文件导出图层
  11. 车间调度标准测试集汇总-FJSP、PFSP、JSP、HFSP和分布式车间调度测试集
  12. 我和ChatGPT聊了聊:它承认自己没有人性
  13. 项目管理工具——项目开发者工具
  14. chrome使用的开源工程介绍
  15. BootLoader 介绍 与 uboot 简介
  16. 鸿蒙系统绿幕,英伟达发布新RTX 30系显卡:全新安培架构 支持8K游戏
  17. uniGUI之UniDBGrid
  18. Google Pay 应用已经发布成功,调起支付回调失败
  19. ECCV22 | 从单目RGB图像中进行类别级6D物体姿态估计的物体级深度重构
  20. 使用paypal的手续费

热门文章

  1. c cuda 指定gpu_GPU并行编程:熟练使用CUDA C语言
  2. c# mysql 插入 和 查询_C#对数据库的操作(增删改查)
  3. java 保存bufferedimage_java - 如何将BufferedImage保存为Fi
  4. php与服务器关系,php与web服务器关系
  5. go mysql recover_golang用panic和recover做业务流程中断的尝试
  6. 10-礼帽与黑帽操作
  7. 分析一下mp4格式的trak -> mdia -> minf -> stbl -> stts、stsc 这两个box信息
  8. php终止脚本执行(exit、die、return)
  9. arraylist从大到小排序_java基础算法之二叉树排序(递归)
  10. centos升级之gcc 升级 gcc-7.3.0安装