一、起步
由于笔者水平有限,学习技术官方文档永远是首先被推荐的,推荐来自Django REST framework官网的快速教程

二、序列化组件
models:
后面的代码将基于这几个表来做操作
1 class BookDetailView(APIView): 2 """ 3 针对单条数据的序列化 4 """ 5 6 def get(self,request,id): 7 8 book=Book.objects.filter(pk=id).first() 9 bs=BookModelSerializers(book,context={'request': request}) 10 return Response(bs.data) 11 12 def put(self,request,id): 13 book=Book.objects.filter(pk=id).first() 14 bs=BookModelSerializers(book,data=request.data) 15 if bs.is_valid(): 16 bs.save() 17 return Response(bs.data) 18 else: 19 return Response(bs.errors) 20 21 def delete(self,request,id): 22 Book.objects.filter(pk=id).delete() 23 24 return Response()
序列化的方法:
方法一: 硬传值
class PublishView(View): def get(self,request): # 方式一: publish_list = list(Publish.objects.all().values("name","email")) # {'name': '苹果出版社', 'email': '123@qq.com'}{'name': '橘子出版社', 'email': '456@qq.com'} return HttpResponse(publish_list)
方法二: model_to_dict(obj)
1 class PublishView(View): 2 def get(self,request): 3 from django.forms.models import model_to_dict 4 publish_list = Publish.objects.all() 5 temp = [] 6 for obj in publish_list: 7 # temp.append({ 8 # "name":obj.name, 9 # "email":obj.email 10 # }) 11 temp.append(model_to_dict(obj)) 12 print(temp, type(temp)) 13 # [{'name': '苹果出版社', 'email': '123@qq.com'}, {'name': '橘子出版社', 'email': '456@qq.com'}] <class 'list'> 14 # [{'id': 1, 'name': '苹果出版社', 'email': '123@qq.com'}, {'id': 2, 'name': '橘子出版社', 'email': '456@qq.com'}] <class 'list'> 15 16 return HttpResponse(temp)
方法三: serializers.serialize("json",publish_list)
class PublishView(View): def get(self,request): from django.core import serializers publish_list = Publish.objects.all() ret = serializers.serialize("json",publish_list) """ [ { "model": "app01.publish", "pk": 1, "fields": { "name": "苹果出版社", "email": "123@qq.com" } }, { "model": "app01.publish", "pk": 2, "fields": { "name": "橘子出版社", "email": "456@qq.com" } } ] """ return HttpResponse(ret)
方法四:rest_framework serializers
1 from rest_framework import serializers 2 3 class PublishSerializers(serializers.Serializer): 4 name = serializers.CharField() 5 email = serializers.EmailField() 6 7 8 class PublishView(View): 9 def get(self,request): 10 # 方式四(推荐) 11 publish_list = Publish.objects.all() 12 ret = PublishSerializers(publish_list, many=True) # queryset 13 # print(ret.data) 14 # print(type(ret.data)) 15 # [OrderedDict([('name', '苹果出版社'), ('email', '123@qq.com')]), 16 # OrderedDict([('name', '橘子出版社'), ('email', '456@qq.com')])] 17 # <class 'rest_framework.utils.serializer_helpers.ReturnList'> 18 """ 19 >>>dict([("name","橘子出版社"),("email","456@qq.com")]) 20 {'name': '橘子出版社', 'email': '456@qq.com'} 21 """ 22 23 return HttpResponse(ret.data)
终结者:ModelSerializer
我们的 PublishSerializers 类中重复了很多包含在Publish模型类(model)中的信息。如果能保证我们的代码整洁,那就更好了。
就像Django提供了Form类和ModelForm类一样,REST framework包括Serializer类和ModelSerializer类。
下面我们换一个稍微复杂的有外键的模型来进行演示:
1 class BookModelSerializers(serializers.ModelSerializer): 2 class Meta: 3 model = Book 4 fields = "__all__" 5 6 #publish=serializers.CharField(source="publish.pk") 7 publish=serializers.HyperlinkedIdentityField( 8 view_name="detailpublish", 9 lookup_field="publish_id", 10 lookup_url_kwarg="pk" 11 ) 12 13 14 class BookView(APIView): 15 def get(self,request): 16 book_list=Book.objects.all() 17 bs=BookModelSerializers(book_list,many=True,context={'request': request}) 18 return Response(bs.data) 19 def post(self,request): 20 # post请求的数据 21 bs=BookModelSerializers(data=request.data) 22 if bs.is_valid(): 23 print(bs.validated_data) 24 bs.save()# create方法 25 return Response(bs.data) 26 else: 27 return Response(bs.errors) 28 29 class BookDetailView(APIView): 30 """ 31 针对单条数据的序列化 32 """ 33 34 def get(self,request,id): 35 36 book=Book.objects.filter(pk=id).first() 37 bs=BookModelSerializers(book,context={'request': request}) 38 return Response(bs.data) 39 40 def put(self,request,id): 41 book=Book.objects.filter(pk=id).first() 42 bs=BookModelSerializers(book,data=request.data) 43 if bs.is_valid(): 44 bs.save() 45 return Response(bs.data) 46 else: 47 return Response(bs.errors) 48 49 def delete(self,request,id): 50 Book.objects.filter(pk=id).delete() 51 52 return Response()
三、APIVIEW
在CBV的基础上,视图类在继承了REST framework的 APIVIEW 后产生了新的调用方法
request的加强:
1 原生request支持的操作 2 print("POST",request.POST) 3 print("body",request.body) 4 # print(request) 5 print(type(request)) 6 from django.core.handlers.wsgi import WSGIRequest 7 新的request支持的操作 8 print("request.data",request.data) 9 print("request.data type",type(request.data))
四、认证和授权
a. 用户url传入的token认证
from django.conf.urls import url, include from web.viewsimport TestView urlpatterns = [ url(r'^test/', TestView.as_view()), ]
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.authentication import BaseAuthentication from rest_framework.request import Request from rest_framework import exceptions token_list = [ 'sfsfss123kuf3j123', 'asijnfowerkkf9812', ] class TestAuthentication(BaseAuthentication): def authenticate(self, request): """ 用户认证,如果验证成功后返回元组: (用户,用户Token) :param request: :return: None,表示跳过该验证; 如果跳过了所有认证,默认用户和Token和使用配置文件进行设置 self._authenticator = None if api_settings.UNAUTHENTICATED_USER: self.user = api_settings.UNAUTHENTICATED_USER() else: self.user = None if api_settings.UNAUTHENTICATED_TOKEN: self.auth = api_settings.UNAUTHENTICATED_TOKEN() else: self.auth = None (user,token)表示验证通过并设置用户名和Token; AuthenticationFailed异常 """ val = request.query_params.get('token') if val not in token_list: raise exceptions.AuthenticationFailed("用户认证失败") return ('登录用户', '用户token') def authenticate_header(self, request): """ Return a string to be used as the value of the `WWW-Authenticate` header in a `401 Unauthenticated` response, or `None` if the authentication scheme should return `403 Permission Denied` responses. """ # 验证失败时,返回的响应头WWW-Authenticate对应的值 pass 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请求,响应内容')
b. 请求头认证
from django.conf.urls import url, include from web.viewsimport TestView urlpatterns = [ 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 exceptions token_list = [ 'sfsfss123kuf3j123', 'asijnfowerkkf9812', ] class TestAuthentication(BaseAuthentication): def authenticate(self, request): """ 用户认证,如果验证成功后返回元组: (用户,用户Token) :param request: :return: None,表示跳过该验证; 如果跳过了所有认证,默认用户和Token和使用配置文件进行设置 self._authenticator = None if api_settings.UNAUTHENTICATED_USER: self.user = api_settings.UNAUTHENTICATED_USER() else: self.user = None if api_settings.UNAUTHENTICATED_TOKEN: self.auth = api_settings.UNAUTHENTICATED_TOKEN() else: self.auth = None (user,token)表示验证通过并设置用户名和Token; AuthenticationFailed异常 """ import base64 auth = 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 the authentication 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
c. 多个认证规则
from django.conf.urls import url, include from web.views.s2_auth import TestView urlpatterns = [ url(r'^test/', TestView.as_view()), ]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.authentication import BaseAuthentication from rest_framework.request import Request from rest_framework import exceptions token_list = [ 'sfsfss123kuf3j123', 'asijnfowerkkf9812', ] class Test1Authentication(BaseAuthentication): def authenticate(self, request): """ 用户认证,如果验证成功后返回元组: (用户,用户Token) :param request: :return: None,表示跳过该验证; 如果跳过了所有认证,默认用户和Token和使用配置文件进行设置 self._authenticator = None if api_settings.UNAUTHENTICATED_USER: self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户 else: self.user = None if api_settings.UNAUTHENTICATED_TOKEN: self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默认值为:None else: self.auth = None (user,token)表示验证通过并设置用户名和Token; AuthenticationFailed异常 """ import base64 auth = request.META.get('HTTP_AUTHORIZATION', b'') if auth: auth = auth.encode('utf-8') else: return None print(auth,'xxxx') auth = auth.split() if not auth or auth[0].lower() != b'basic': raise exceptions.AuthenticationFailed('验证失败') if len(auth) != 2: raise exceptions.AuthenticationFailed('验证失败') username, part, password = base64.b64decode(auth[1]).decode('utf-8').partition(':') if username == 'alex' and password == '123': return ('登录用户', '用户token') else: raise exceptions.AuthenticationFailed('用户名或密码错误') def authenticate_header(self, request): """ Return a string to be used as the value of the `WWW-Authenticate` header in a `401 Unauthenticated` response, or `None` if the authentication scheme should return `403 Permission Denied` responses. """ # return 'Basic realm=api' pass class Test2Authentication(BaseAuthentication): def authenticate(self, request): """ 用户认证,如果验证成功后返回元组: (用户,用户Token) :param request: :return: None,表示跳过该验证; 如果跳过了所有认证,默认用户和Token和使用配置文件进行设置 self._authenticator = None if api_settings.UNAUTHENTICATED_USER: self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户 else: self.user = None if api_settings.UNAUTHENTICATED_TOKEN: self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默认值为:None else: self.auth = None (user,token)表示验证通过并设置用户名和Token; AuthenticationFailed异常 """ val = request.query_params.get('token') if val not in token_list: raise exceptions.AuthenticationFailed("用户认证失败") return ('登录用户', '用户token') def authenticate_header(self, request): """ Return a string to be used as the value of the `WWW-Authenticate` header in a `401 Unauthenticated` response, or `None` if the authentication scheme should return `403 Permission Denied` responses. """ pass class TestView(APIView): authentication_classes = [Test1Authentication, Test2Authentication] permission_classes = [] def get(self, request, *args, **kwargs): print(request.user) print(request.auth) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')
d. 认证和权限
from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r'^test/', TestView.as_view()), ]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.authentication import BaseAuthentication from rest_framework.permissions import BasePermission from rest_framework.request import Request from rest_framework import exceptions token_list = [ 'sfsfss123kuf3j123', 'asijnfowerkkf9812', ] class TestAuthentication(BaseAuthentication): def authenticate(self, request): """ 用户认证,如果验证成功后返回元组: (用户,用户Token) :param request: :return: None,表示跳过该验证; 如果跳过了所有认证,默认用户和Token和使用配置文件进行设置 self._authenticator = None if api_settings.UNAUTHENTICATED_USER: self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户 else: self.user = None if api_settings.UNAUTHENTICATED_TOKEN: self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默认值为:None else: self.auth = None (user,token)表示验证通过并设置用户名和Token; AuthenticationFailed异常 """ val = request.query_params.get('token') if val not in token_list: raise exceptions.AuthenticationFailed("用户认证失败") return ('登录用户', '用户token') def authenticate_header(self, request): """ Return a string to be used as the value of the `WWW-Authenticate` header in a `401 Unauthenticated` response, or `None` if the authentication scheme should return `403 Permission Denied` responses. """ pass class 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 True class TestView(APIView): # 认证的动作是由request.user触发 authentication_classes = [TestAuthentication, ] # 权限 # 循环执行所有的权限 permission_classes = [TestPermission, ] def get(self, request, *args, **kwargs): # self.dispatch print(request.user) print(request.auth) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容') views.py
e. 全局使用
上述操作中均是对单独视图进行特殊配置,如果想要对全局进行配置,则需要再配置文件中写入即可。
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 TestView urlpatterns = [ url(r'^test/', TestView.as_view()), ]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response class TestView(APIView): def get(self, request, *args, **kwargs): # self.dispatch print(request.user) print(request.auth) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容') views.py
五、用户访问次数/频率限制
a. 基于用户IP限制访问频率
urls.py
views.pyb. 基于用户IP显示访问频率(利于Django缓存)
settings.py
urls.py
views.pyc. view中限制请求频率
settings.py
urls.py
views.pyd. 匿名时用IP限制+登录时用Token限制
settings.py
urls.py
views.pye. 全局使用
settings六、解析器(parser)
根据请求头 content-type 选择对应的解析器就请求体内容进行处理。
a. 仅处理请求头content-type为application/json的请求体
urls.py
views.pyb. 仅处理请求头content-type为application/x-www-form-urlencoded 的请求体
urls.py
views.pyc. 仅处理请求头content-type为multipart/form-data的请求体
urls.py
views.py
upload.htmld. 仅上传文件
urls.py
views.py
upload.htmle. 同时多个Parser
当同时使用多个parser时,rest framework会根据请求头content-type自动进行比对,并使用对应parser
urls.py
views.pyf. 全局使用
settings.py
urls.py
views.py注意:个别特殊的值可以通过Django的request对象 request._request 来进行获取
七、分页
a. 根据页码进行分页
urs.py
views.pyb. 位置和个数进行分页
urls.py
views.pyc. 游标分页
urls.py
views.py八、路由系统
a. 自定义路由
urls.py
views.pyb. 半自动路由
urls.py
views.pyc. 全自动路由
urls.py
views.py九、视图
a. GenericViewSet
urls.py
views.pyb. ModelViewSet(自定义URL)
urls.py
views.pyc. ModelViewSet(rest framework路由)
urls.py
views.py参考资料:
武佩奇:https://www.cnblogs.com/wupeiqi/articles/7805382.htmlYUAN先生: https://www.cnblogs.com/yuanchenqi/articles/8719520.html