一版本
自定义版本基于URL获取版本
定义版本类
class ParamVersion(): def determine_version(self, request, *args, **kwargs): version = request.query_params.get('version') #等于request._request.GET.get('version) print(request.query_params) return version
URL
from django.conf.urls import url, include from app01.views import TestView urlpatterns = [ url(r'^test/', TestView.as_view(),name='test'), ]
views
class TestView(APIView): versioning_class = URLPathVersioning # 基于URL正则获取版本获取版本 def get(self, request, *args, **kwargs): # 获取版本 print(request.version) # 获取版本管理的类 print(request.versioning_scheme) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容')
框架QueryParameterVersioning模块基于URL获取版本
settings配置
REST_FRAMEWORK = { 'DEFAULT_VERSION': 'v1', # 默认版本 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本 'VERSION_PARAM': 'version' # URL中获取值的key }
URL
from django.conf.urls import url, include from app01.views import TestView urlpatterns = [ url(r'^test/', TestView.as_view(),name='test'), ]
views
class TestView(APIView): versioning_class = QueryParameterVersioning # 基于URL获取版本 def get(self, request, *args, **kwargs): # 获取版本 print(request.version) # 获取版本管理的类 print(request.versioning_scheme) # 反向生成URL reverse_url = request.versioning_scheme.reverse('test', request=request) print(reverse_url) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容')
框架URLPathVersioning模块基于URL正则获取版本
url
from django.conf.urls import url, include from app01.views import TestView urlpatterns = [ url(r'^(?P<version>[v1|v2]+)/test/', TestView.as_view(), name='test'), ]
view
class TestView(APIView): versioning_class = URLPathVersioning # 基于URL正则获取版本获取版本 def get(self, request, *args, **kwargs): # 获取版本 print(request.version) # 获取版本管理的类 print(request.versioning_scheme) # 反向生成URL reverse_url = request.versioning_scheme.reverse('test', request=request) print(reverse_url) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容')
其他版本控制类用from rest_framework import versioning查看源码
全局设置版本控制
REST_FRAMEWORK = {
"DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
}
二 认证
自定义认证类,用户url传入token
url
urlpatterns = [ url(r'^auth/',views.AuthView.as_view(),name='auth'), url(r'^order/',views.OrderView.as_view(),name='order'), ]
认证类
class Authenticate(BaseAuthentication): #继承所有认证类父类 def authenticate(self,request): token = request._request.GET.get('token') token_obj = models.UserToken.objects.filter(token=token).first() if not token_obj: raise exceptions.AuthenticationFailed('用户认证失败') # 在rest framework内部会将整个两个字段赋值给request,以供后续操作使用 return (token_obj.user, token_obj) def authenticate_header(self, request): #验证失败时候的弹窗,一般不用不关注 return 'Basic realm="api"'
md5生成token
1 def md5(user): 2 import hashlib 3 import time 4 ctime = str(time.time()) 5 m=hashlib.md5(bytes(user,encoding='utf-8')) 6 m.update(bytes(ctime,encoding='utf-8')) 7 return m.hexdigest()
view
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import QueryParameterVersioning,URLPathVersioning
from rest_framework import versioning
from rest_framework.response import Response
1 # 登录 2 class AuthView(APIView): 3 def post(self,request,*args,**kwargs): 4 ret = {'code':1000,'msg':None} 5 try: 6 user = request._request.POST.get('username') 7 pwd = request._request.POST.get('password') 8 obj = models.UserInfo.objects.filter(username=user,password=pwd).first() 9 if not obj: 10 ret['code'] = 1001 11 ret['msg'] = "用户名或密码错误" 12 # 为登录用户创建token 13 token = md5(user) 14 # 存在就更新,不存在就创建 15 models.UserToken.objects.update_or_create(user=obj,defaults={'token':token}) 16 ret['token'] = token 17 except Exception as e: 18 ret['code'] = 1002 19 ret['msg'] = '请求异常' 21 return JsonResponse(ret) 22 23 class OrderView(APIView): 24 """ 25 订单相关业务 26 """ 27 authentication_classes = [Authenticate,] #需要认证的业务 28 def get(self,request,*args,**kwargs): 29 print(request.user) 30 print(request.auth) 31 ret = {'code':1000,'msg':None,'data':None} 32 try: 33 ret['data'] = ORDER_DICT 34 except Exception as e: 35 pass 36 return JsonResponse(ret)
框架自带认证类
from rest_framework.authentication import BaseAuthentication
全局配置认证
1 REST_FRAMEWORK = { 2 'UNAUTHENTICATED_USER': None, 3 'UNAUTHENTICATED_TOKEN': None, 4 "DEFAULT_AUTHENTICATION_CLASSES": [ 5 "web.utils.TestAuthentication", #认证类路径 6 ], 7 8 } 9 settings.py
全局认证时碰上不需要认证的类,只需要在类配置认证类为空列表就行,
1 class OrderView(APIView): 2 authentication_classes = [] 3 def get(self,request,*args,**kwargs): 4 print(request.user) 5 print(request.auth)
认证源码执行顺序
三 权限
权限控制类
1 class SVIPPermission(BasePermission): 2 message = "必须是SVIP才能访问" 3 def has_permission(self,request,view): 4 if request.user.user_type != 3: 5 return False 6 return True
返回False没有权限,True有权限
view
1 class OrderView(APIView): 2 """ 3 订单相关业务(只有SVIP用户有权限) 4 """ 5 authentication_classes = [Authenticate,] 6 permission_classes = [SVIPPermission,] 7 def get(self,request,*args,**kwargs): 8 print(request.user) 9 print(request.auth) 10 ret = {'code':1000,'msg':None,'data':None} 11 try: 12 ret['data'] = ORDER_DICT 13 except Exception as e: 14 pass 15 return JsonResponse(ret)
全局配置权限
REST_FRAMEWORK = { "DEFAULT_PERMISSION_CLASSES:['api.utils.permission.SVIPPermission'], }
源码流程图
四 用户访问次数/频率限制
简单所有权限类父类实现
1 from rest_framework.throttling import BaseThrottle 2 import time 3 VISIT_RECORD = {} 4 class VisitThrottle(BaseThrottle): 5 6 def __init__(self): 7 self.history = None 8 9 def allow_request(self,request,view): 10 # 1. 获取用户IP 11 remote_addr = self.get_ident(request) 12 13 ctime = time.time() 14 if remote_addr not in VISIT_RECORD: 15 VISIT_RECORD[remote_addr] = [ctime,] 16 return True 17 history = VISIT_RECORD.get(remote_addr) 18 self.history = history 19 20 while history and history[-1] < ctime - 60: 21 history.pop() 22 23 if len(history) < 3: 24 history.insert(0,ctime) 25 return True 26 27 # return True # 表示可以继续访问 28 # return False # 表示访问频率太高,被限制 29 30 def wait(self): 31 # 还需要等多少秒才能访问 32 ctime = time.time() 33 return 60 - (ctime - self.history[-1])
view
1 class ThrottView(APIView): 2 throttle_classes = [VisitThrottle] 3 def get(self,request, *args, **kwargs): 4 5 return HttpResponse("限流时间之内访问页面")
系统频率限制类
基于用户IP显示访问频率(利于Django缓存) 实现
view
from rest_framework.throttling import BaseThrottle,SimpleRateThrottle class VisitThrottle(SimpleRateThrottle): scope = "Luffy" # 数据属性对应settings 的key,value是单位时间访问次数 def get_cache_key(self, request, view): return self.get_ident(request)
settings配置
REST_FRAMEWORK = { "DEFAULT_THROTTLE_RATES":{ "Luffy":'3/m', } }
更多其他方式查看 >>> from rest_framework.throttling import BaseThrottle
五 解析器
根据请求头 content-type 选择对应的解析器就请求体内容进行处理
url
1 from django.conf.urls import url, include 2 from app01.views import TestView 3 from app01 import views 4 5 urlpatterns = [ 6 url(r'^paser/',views.PaserView.as_view(),name='paser'), 7 ]
view
1 from rest_framework.parsers import JSONParser,FormParser 2 class PaserView(APIView): 3 parser_classes = [FormParser,JSONParser] 4 def get(self,request, *args, **kwargs): 5 print(request.data) 6 return HttpResponse("解析器") 7 8 def post(self,request, *args, **kwargs): 9 print(request.data) 10 return HttpResponse("解析器")
更多内置解析器查看
from rest_framework.parsers import JSONParser
解析Content-type头和对应解析类型
a. 仅处理请求头content-type为application/json的请求体
b. 仅处理请求头content-type为application/x-www-form-urlencoded 的请求体
c. 仅处理请求头content-type为multipart/form-data的请求体
d. 仅上传文件FileUploadParser
全局使用
1 REST_FRAMEWORK = { 2 'DEFAULT_PARSER_CLASSES':[ 3 'rest_framework.parsers.JSONParser' 4 'rest_framework.parsers.FormParser' 5 'rest_framework.parsers.MultiPartParser' 6 ] 7 8 }
六 序列化
Serializer
序列化类
class StuSerializers(serializers.Serializer): id = serializers.IntegerField() name = serializers.CharField() # 一对一和一对多正向查询 source ='字段名.跨表的字段名' stu_grade = serializers.CharField(source='stu_grade.title') addr = serializers.CharField(source='stu_addr.addr')
models
1 class Student(models.Model): 2 name = models.CharField(max_length=16) 3 stu_grade = models.ForeignKey(to="Grade",on_delete=models.CASCADE) 4 stu_addr = models.OneToOneField(to='Addr',on_delete=models.CASCADE) 5 6 class Grade(models.Model): 7 title = models.CharField(max_length=16) 8 9 10 class Addr(models.Model): 11 addr = models.CharField(max_length=100)
url
1 url(r'^student/',views.StudentView.as_view(),name='student'),
views
1 class StudentView(APIView): 2 def get(self,request,*args,**kwargs): 3 stu_list = models.Student.objects.all().first() 4 ser = StuSerializers(instance=stu_list) 5 return Response(ser.data)
from rest_framework.response import Response自动将序列化好的类转为json格式发给前端
序列化对个对象 添加many=True
ser = StuSerializers(instance=stu_list,many=True)
自定义显示字段
1 class UserinfoSerializes(serializers.Serializer): 2 username = serializers.CharField() 3 password = serializers.CharField() 4 user_type = serializers.CharField(source='get_user_type_display') #显示choices字段名称get_字段名_display 5 gp = serializers.CharField(source='group.title') # onetoone foreignkey 跨表 6 rls = serializers.SerializerMethodField() #自定义显示字段manttomany 7 def get_rls(self,row): 8 role_obj_list = row.roles.all() 9 ret = [] 10 for item in role_obj_list: 11 ret.append({"id":item.id,"title":item.title}) 12 return ret
自定义显示字段用于ManytoMany 或者 多对一反向查询时
显示choices字段名称get_字段名_display
ModelSerializer
定义序列化类
1 class GradeSerializers(serializers.ModelSerializer): 2 stu_grade_id = serializers.IntegerField(write_only=True) 3 stu_addr_id = serializers.IntegerField(write_only=True) 4 class Meta: 5 model = models.Student 6 fields = '__all__' 7 depth = 1 #层数
write_only=True,只做反序列化,保存
read_only=True,只做序列化,读取
1 class GradeView(APIView): 2 def get(self,request,*args,**kwargs): 3 grade_list = models.Student.objects.all() 4 ser = GradeSerializers(instance=grade_list,many=True) 5 print(ser) 6 return Response(ser.data) 7 8 def post(self,request,*args,**kwargs): 9 ser = GradeSerializers(data=request.data) 10 if ser.is_valid(): #客户端提交数据校验 11 print('validated_data',ser.validated_data) #提交成功字段 12 # ser.save() # 没有外键字段使用 ,提交到数据库方式一,需要指定保存字段write_only=True 13 models.Student.objects.create( 14 name = ser.validated_data['name'], 15 stu_grade_id = ser.validated_data['stu_grade_id'], 16 stu_addr_id = ser.validated_data['stu_addr_id'], 17 ) 18 return HttpResponse('增加成功') 19 20 else: 21 print('errors',ser.errors) #验证失败字段 22 return HttpResponse('ok')
七 分页
url
1 urlpatterns = [ 2 url('page_ud/', views.PageView.as_view()), 3 ]
根据页码进行分页
1 #a. 根据页码进行分页 http://127.0.0.1:8000/page_ud/?page=1&size=3 2 class MyPagePagination(PageNumberPagination): 3 page_size = 2 #每页显示多少条 4 page_size_query_param = 'size' #url传递参数size,一页显示多少条数据 5 page_query_param = 'page' #URL传递页数,第几页 6 max_page_size = 5
位置和个数进行分页
1 class MyPagePagination(LimitOffsetPagination): 2 default_limit = 3 3 limit_query_param = 'limit' # 查几条数据 4 offset_query_param = 'offset' #从第几条开始 5 max_limit = 5
游标分页
1 # c. 游标分页 http://127.0.0.1:8000/page_ud/ 2 # 将页码加密 必须返回return pg.get_paginated_response(ser.data)这个 3 class MyPagePagination(CursorPagination): 4 # URL传入的游标参数 5 cursor_query_param = 'cursor' 6 # 默认每页显示的数据条数 7 page_size = 2 8 # URL传入的每页显示条数的参数 9 page_size_query_param = 'page_size' 10 # 每页显示数据最大条数 11 max_page_size = 1000 12 # 根据ID从大到小排列 13 ordering = "id"
view
1 class PageView(APIView): 2 def get(self,request,*args,**kwargs): 3 page_list = models.Student.objects.all() 4 pg = MyPagePagination() 5 # 实例化分页器 6 page_ser = pg.paginate_queryset(queryset=page_list, request=request, view=self) 7 8 ser = GradeSerializers(instance=page_ser,many=True) 9 10 return Response(ser.data) 11 # return pg.get_paginated_response(ser.data)
八 视图
GenericAPIView
源码 继承了APIView
url
1 urlpatterns = [ 2 url('stu/', views.StuView.as_view()) 3 ]
view
1 # 继承GenericAPIView 继承APIView 2 # 继承GenericAPIView 从自定义的分页器和序列化类中实现一系列序列化 3 from rest_framework.generics import GenericAPIView 4 class StuView(GenericAPIView): 5 queryset = models.Student.objects.all() 6 serializer_class = GradeSerializers #自己定义序列化类 7 pagination_class = MyPagePagination #自已定义分页类 8 9 def get(self,request,*args,**kwargs): 10 page_list = models.Student.objects.all() 11 pg = MyPagePagination() 12 # 实例化分页器 13 page_ser = pg.paginate_queryset(queryset=page_list, request=request, view=self) 14 ser = GradeSerializers(instance=page_ser,many=True) 15 return Response(ser.data)
GenericViewSet
1 urlpatterns = [ 2 url('stu/', views.StuView1.as_view({'get':'list'})), 3 ]
view
1 # GenericViewSet 需要在路由配置url('stu/', views.StuView1.as_view({'get':'list'})), 2 # 将get请求印射到list方法 3 # 相当于起别名一样的视图 也可以post put请求 4 from rest_framework.viewsets import GenericViewSet 5 class StuView1(GenericViewSet): 6 7 def list(self,request,*args,**kwargs): 8 return HttpResponse('...')
ModelViewSet
url
1 urlpatterns = [ 2 url(r'^studd/(?P<pk>d+)$', views.StuView3.as_view({'get': 'retrieve','delete':'destroy','put':'update','patch':'partial_update'})), 3 4 ]
view
1 class ModelViewSet(mixins.CreateModelMixin, 2 mixins.RetrieveModelMixin, 3 mixins.UpdateModelMixin, 4 mixins.DestroyModelMixin, 5 mixins.ListModelMixin, 6 GenericViewSet):继承了增删改查所有的方法 7 from rest_framework.viewsets import ModelViewSet 8 class StuView3(ModelViewSet): 9 queryset = models.Student.objects.all() 10 serializer_class = GradeSerializers #定义序列化类 11 pagination_class = MyPagePagination #定义分页类
九 渲染器
视图配置
1 from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer 2 class page_udView(ModelViewSet): 3 # renderer_classes = [JSONRenderer,] #数据渲染成json格式 4 renderer_classes = [JSONRenderer,BrowsableAPIRenderer] #数据渲染成json格式,浏览器渲染 5 6 7 queryset = Page.objects.all() 8 serializer_class = PagePagination 9 pagination_class = MyPagePagination
查看各种渲染器
from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
JSONRenderer #media_type = 'application/json'
TemplateHTMLRenderer #media_type = 'text/html'