一、什么是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" }
8.返回结果,针对不同操作,服务器向用户返回的结果应该符合以下规范。
GET /collection:返回资源对象的列表(数组) GET /collection/resource:返回单个资源对象 POST /collection:返回新生成的资源对象 PUT /collection/resource:返回完整的资源对象 PATCH /collection/resource:返回完整的资源对象 DELETE /collection/resource:返回一个空文档
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" }}
摘自: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 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)
四、基于Django Rest framework框架实现
1.基本流程
from django.conf.urls import url, include from web.views.s1_api import TestViewurlpatterns = [url(r'^test/', TestView.as_view()), ]
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请求,响应内容')
上述是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()), ]
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请求,响应内容')
(2)请求头认证
from django.conf.urls import url, include from web.viewsimport TestViewurlpatterns = [url(r'^test/', TestView.as_view()), ]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.authentication import BaseAuthentication from rest_framework.request import Request from rest_framework import 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请求,响应内容')
(3)多个认证规则
from django.conf.urls import url, include from web.views.s2_auth import TestViewurlpatterns = [url(r'^test/', TestView.as_view()), ]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.authentication import BaseAuthentication from rest_framework.request import Request from rest_framework import 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请求,响应内容')
(4)认证和权限
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'^test/', TestView.as_view()), ]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.authentication import BaseAuthentication from rest_framework.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请求,响应内容')
(5)全局使用
上述操作中均是对单独试图进行特殊操作配置,如果要对全局进行配置,则需要在配置文件中写入即可。
REST_FRAMEWORK = {'UNAUTHENTICATED_USER': None,'UNAUTHENTICATED_TOKEN': None,"DEFAULT_AUTHENTICATION_CLASSES": ["web.utils.TestAuthentication",],"DEFAULT_PERMISSION_CLASSES": ["web.utils.TestPermission",], }
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'^test/', TestView.as_view()), ]
#!/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请求,响应内容')
3.用户访问次数/频率限制
(1)基于用户IP限制访问频率
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'^test/', TestView.as_view()), ]
#!/usr/bin/env python # -*- coding:utf-8 -*- import time from rest_framework.views import APIView from rest_framework.response import 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)
(2)基于用户IP显示访问频率(利用Django缓存)
REST_FRAMEWORK = {'DEFAULT_THROTTLE_RATES': {'test_scope': '10/m',}, }
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'^test/', TestView.as_view()), ]
#!/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)
(3)view中限制请求频率
REST_FRAMEWORK = {'DEFAULT_THROTTLE_RATES': {'xxxxxx': '10/m',}, }
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'^test/', TestView.as_view()), ]
#!/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)
(4)匿名时用IP限制+登录时用Token限制
REST_FRAMEWORK = {'UNAUTHENTICATED_USER': None,'UNAUTHENTICATED_TOKEN': None,'DEFAULT_THROTTLE_RATES': {'luffy_anon': '10/m','luffy_user': '20/m',}, }
from django.conf.urls import url, include from web.views.s3_throttling import TestViewurlpatterns = [url(r'^test/', TestView.as_view()), ]
#!/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请求,响应内容')
(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',}, }
4.版本
(1)基于url的get传参方式
如:/users?version=v1
REST_FRAMEWORK = {'DEFAULT_VERSION': 'v1', # 默认版本'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本'VERSION_PARAM': 'version' # URL中获取值的key }
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'^test/', TestView.as_view(),name='test'), ]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.versioning import 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请求,响应内容')
(2)基于url的正则方式
如:/v1/users/
REST_FRAMEWORK = {'DEFAULT_VERSION': 'v1', # 默认版本'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本'VERSION_PARAM': 'version' # URL中获取值的key }
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'^(?P<version>[v1|v2]+)/test/', TestView.as_view(), name='test'), ]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.versioning import 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请求,响应内容')
(3)基于accept请求方式
如:Accept: application/json; version=1.0
REST_FRAMEWORK = {'DEFAULT_VERSION': 'v1', # 默认版本'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本'VERSION_PARAM': 'version' # URL中获取值的key }
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'^test/', TestView.as_view(), name='test'), ]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.versioning import 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请求,响应内容')
(4)基于主机名方法
如:v1.example.com
ALLOWED_HOSTS = ['*'] REST_FRAMEWORK = {'DEFAULT_VERSION': 'v1', # 默认版本'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本'VERSION_PARAM': 'version' # URL中获取值的key }
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'^test/', TestView.as_view(), name='test'), ]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.versioning import 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请求,响应内容')
(5)基于Django路由系统的namespace
如:example.com/v1/users/
REST_FRAMEWORK = {'DEFAULT_VERSION': 'v1', # 默认版本'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本'VERSION_PARAM': 'version' # URL中获取值的key }
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')),]
#!/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请求,响应内容')
(6)全局使用
REST_FRAMEWORK = {'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning",'DEFAULT_VERSION': 'v1','ALLOWED_VERSIONS': ['v1', 'v2'],'VERSION_PARAM': 'version' }
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'), ]
#!/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请求,响应内容')
(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'), ]
#!/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请求,响应内容')
(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'), ]
#!/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请求,响应内容')
<!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>
(4)仅上传文件
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'test/(?P<filename>[^/]+)', TestView.as_view(), name='test'), ]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.request import Request from rest_framework.parsers import 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请求,响应内容')
<!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>
(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'), ]
#!/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请求,响应内容')
(6)全局使用
REST_FRAMEWORK = {'DEFAULT_PARSER_CLASSES':['rest_framework.parsers.JSONParser''rest_framework.parsers.FormParser''rest_framework.parsers.MultiPartParser']}
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'test/', TestView.as_view(), name='test'), ]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import 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请求,响应内容')
注意:个别特殊的值可以通过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'), ]
#!/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请求,响应内容')
(2)基于Model自动生成字段
from django.conf.urls import url, include from web.views.s6_serializers import TestViewurlpatterns = [url(r'test/', TestView.as_view(), name='test'), ]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework 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请求,响应内容')
(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'), ]
#!/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请求,响应内容')
(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'), ]
#!/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请求,响应内容')
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()), ]
#!/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
(2)位置和个数进行分页
from django.conf.urls import url, include from web.views import s9_paginationurlpatterns = [url(r'^test/', s9_pagination.UserViewSet.as_view()), ]
#!/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
(3)游标分页
from django.conf.urls import url, include from web.views import s9_paginationurlpatterns = [url(r'^test/', s9_pagination.UserViewSet.as_view()), ]
#!/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
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()) ]
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('...')
(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'})), ]
#!/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
(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)), ]
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
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'), ]
#!/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
(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'})), ]
#!/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
(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)), ]
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
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()), ]
#!/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)
(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)
(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)
(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()), ]
#!/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')
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body>{{ user }}{{ pwd }}{{ ut }} </body> </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')
注意:如果同时多个存在时,自动根据URL后缀来选择渲染器。