DRF

大V

一版本  

 自定义版本基于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
View Code

全局认证时碰上不需要认证的类,只需要在类配置认证类为空列表就行,

1 class OrderView(APIView):
2     authentication_classes = []
3     def get(self,request,*args,**kwargs):
4         print(request.user)
5         print(request.auth)
View Code

认证源码执行顺序

三  权限

权限控制类

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
View Code

返回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)
View Code

全局配置权限

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 Code

view

1 class ThrottView(APIView):
2     throttle_classes = [VisitThrottle]
3     def get(self,request, *args, **kwargs):
4 
5         return HttpResponse("限流时间之内访问页面")
View Code

系统频率限制类

基于用户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 Code

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("解析器")
View Code

更多内置解析器查看

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 }
View Code

 六 序列化

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)
View Code

url

1 url(r'^student/',views.StudentView.as_view(),name='student'),
View Code

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)
View Code
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
View Code

自定义显示字段用于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  #层数
View Code
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')
View Code

七 分页

url

1 urlpatterns = [
2     url('page_ud/', views.PageView.as_view()),
3 ]
View Code
根据页码进行分页
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
View Code
位置和个数进行分页
1 class MyPagePagination(LimitOffsetPagination):
2     default_limit = 3
3     limit_query_param = 'limit'  # 查几条数据
4     offset_query_param = 'offset' #从第几条开始
5     max_limit = 5
View Code

游标分页

 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 Code

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)  
View Code

八 视图

GenericAPIView

源码  继承了APIView

url

1 urlpatterns = [
2     url('stu/', views.StuView.as_view())
3 ]
View Code

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)
View Code

GenericViewSet

1 urlpatterns = [
2     url('stu/', views.StuView1.as_view({'get':'list'})),
3 ]
View Code

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('...')
View Code

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 Code

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  #定义分页类
View Code

九 渲染器

视图配置

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
View Code
查看各种渲染器
from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
JSONRenderer  #media_type = 'application/json'
TemplateHTMLRenderer  #media_type = 'text/html'







原文地址:https://www.cnblogs.com/sunny666/p/13501727.html