脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Python - python drf各类组件的用法和作用

python drf各类组件的用法和作用

2021-08-24 00:19Dimple_Y Python

这篇文章主要介绍了python drf各类组件的用法和作用,帮助大家更好的理解和学习python,感兴趣的朋友可以了解下

DRF组件的用法和作用

认证

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
  自定义认证的类
 """
 from rest_framework.authentication import BaseAuthentication
 from rest_framework.exceptions import AuthenticationFailed
 from authapp.models import UserToken
 class MyOrderAuthentication(BaseAuthentication):
    在这里实现认证的逻辑
   def authenticate(self, request):
     token = request._request.GET.get('token')
     # 获取到token之后,需要在数据库中查找token
     obj = UserToken.objects.filter(token=token).first()
     if not obj:
       # 没有通过认证
       raise AuthenticationFailed('认证失败')
     # 返回元组( user, auth )
     return (obj.user, obj)
 """
 
使用局部配置(在视图函数中)
 """
 class OrderView(APIView):
   # 通过authentication_classes设置认证类
   authentication_classes = [MyOrderAuthentication,]
   # 通过authentication_classes设置为空列表,就不再进行认证了
   # authentication_classes = []
 """
 
全局配置
 """
 REST_FRAMEWORK = {
   'DEFAULT_AUTHENTICATION_CLASSES':['unitls.authentication.MyOrderAuthentication'],
 }
 """
 
设置匿名用户
 """
 REST_FRAMEWORK = {
   'UNAUTHENTICATED_USER': lambda :"匿名用户",
   'UNAUTHENTICATED_TOKEN': lambda :'123456',
 }
 """
 
## 最最重要的,理清认证的源代码

权限

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
自定义权限类
 """
  from rest_framework.permissions import BasePermission
  class MyOrderPermission(BasePermission):
    #自定义权限认证的类,必须要实现has_permission方法
    message = '你不是超级用户,没有权限访问'
    def has_permission(self, request, view):
    
      #Return `True` if permission is granted, `False` otherwise.
      #返回True表示有权限访问,返回False表示没有权限访问
      if request.user.user_type != 3:
        return False
      return True
 """
 
 局部使用
 """
 class OrderView(APIView):
 
    # permission_classes设置权限类
    permission_classes = [MyOrderPermission,]
    # 通过authentication_classes设置为空列表,就不再进行权限认证了
    permission_classes = []
 """
 
 全局的设定
 """
 REST_FRAMEWORK = {
   'DEFAULT_PERMISSION_CLASSES':['unitls.permission.MyOrderPermission'],
 }
 """
 
 最最重要的,理清权限认证的源代码

分页

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
自定义分页类PageNumberPagination
 # 自定制分页类
 class MyPageNumberPagination(PageNumberPagination):
   """http://127.0.0.1:8000/api/userpage/?page=1&pagesize=10"""
   # page_size每一返回多少条
   page_size = 5
   # 设置分页的参数名
   page_query_param = 'page'
   # 设置每页返回数据量的参数名
   page_size_query_param = 'pagesize'
   # 设置每页最大返回的条数
   max_page_size = 6
 
使用
  class UsersPageView(APIView):
    
    def get(self,request,*args,**kwargs):
      # 获取表中所有用户的row(记录)
      obj = models.UserInfo.objects.all()
      #实例化分页的类
      #page_obj = PageNumberPagination()
      page_obj = MyPageNumberPagination()
      #获取分页数据
      page_data = page_obj.paginate_queryset( queryset=obj,request=request,view=self)
      # 序列化
      ser = UsersSerializer(instance=page_data,many=True)
 
      # return Response(ser.data)
      #get_paginated_response会返回上一页下一页和总条数
      return page_obj.get_paginated_response(ser.data)
 
 自定义分页类LimitOffsetPagination
 from rest_framework.pagination import LimitOffsetPagination
 
 class MyLimitOffsetPagination(LimitOffsetPagination):
   """http://127.0.0.1:8000/api/userpage/?limit=10&offset=0"""
   default_limit = 5
   limit_query_param = 'limit'
   offset_query_param = 'offset'
   max_limit = 7
 
 
 自定义分页类CursorPagination(会对分页参数进行加密)
 from rest_framework.pagination import CursorPagination
 
 class MyCursorPagination(CursorPagination):
   """http://127.0.0.1:8000/api/userpage/?cursor=cD01"""
   cursor_query_param = 'cursor'
   page_size = 4
   #返回数据市的排序的方式
   ordering = '-id'
   max_page_size = 8
 
  设置全局的分页
  """
    REST_FRAMEWORK = {
      'DEFAULT_PAGINATION_CLASS':'unitl.pagination.MyCursorPagination',
      'PAGE_SIZE':3
    }
  """

视图

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
以前 (Django的View)
 """
   class MyView(View)
     .....
 """
 
 现在(rest_framework的APIView)
 """
   class MyView(APIView)
   .....
 """
 
 其他视图的使用
 第一个:GenericAPIView 视图的使用 (跟继承自APIViewq其实一样,只是我们在外面逻辑,
   GenericAPIView在内部c定制方法帮我们实现了)
 """
 from rest_framework.generics import GenericAPIView
 class BookinfoSeralizer(serializers.ModelSerializer):
   
   class Meta:
     model = models.BookInfo
     fields = "__all__"
 class BookView(GenericAPIView):
   # queryset: 设置获取的数据
   queryset = models.BookInfo.objects.all()
   # serializer_class: 设置序列化的类
   serializer_class = BookinfoSeralizer
   # pagination_class : 设置分页的类
   pagination_class = MyPageNumberPagination
   def get(self,request,*args,**kwargs):
     obj = self.get_queryset() #=> obj = models.BookInfo.objects.all()
     # 获取当前分页的数据
     page_data = self.paginate_queryset(obj) #=>page_obj = MyPageNumberPagination() #获取分页数据page_data = page_obj.paginate_queryset()
     # 获取序列化之后的数据
     ser = self.get_serializer(instance=page_data,many=True) #->ser = BookinfoSeralizer(instance=page_data,many=True)
     return Response(ser.data)
 """
   
  第二个:GenericViewSet 视图的如下使用,注意路由会发生变化
   """
   class BookView(GenericViewSet):
     # queryset: 设置获取的数据
     queryset = models.BookInfo.objects.all()
     # serializer_class: 设置序列化的类
     serializer_class = BookinfoSeralizer
     # pagination_class : 设置分页的类
     pagination_class = MyPageNumberPagination
     
     def list(self,request,*args,**kwargs):
       
       obj = self.get_queryset() #=> obj = models.BookInfo.objects.all()
       # 获取当前分页的数据
       page_data = self.paginate_queryset(obj) #=>page_obj = MyPageNumberPagination() #获取分页数据page_data = page_obj.paginate_queryset(
       # 获取序列化之后的数据
       ser = self.get_serializer(instance=page_data,many=True) #->ser = BookinfoSeralizer(instance=page_data,many=True)
       
       return Response(ser.data)
   """
   路由会发生变化,配置如下
   """
   url(r"bookpage/$",views.BookView.as_view({'get': 'list'}),name='bookpage')
   """
   
   第三个:ListModelMixin,CreateModelMixin,RetrieveModelMixin,
   DestroyModelMixin,UpdateModelMixin 等视图的使用
   
   """
   from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,DestroyModelMixin,UpdateModelMixin
   from rest_framework.viewsets import GenericViewSet
   # ListModelMixin : 返回列表数据据( get请求)
   # CreateModelMixin : 新增一条数据 (Post请求)
   # RetrieveModelMixin, : 获取详情数据 (get请求)
   # DestroyModelMixin,  : 删除数据的时候 (delete)
   # UpdateModelMixin : 跟新数据的时候使用 (put)
 
   class BookView(ListModelMixin,RetrieveModelMixin,CreateModelMixin,DestroyModelMixin,UpdateModelMixin,GenericViewSet):
     # queryset: 设置获取的数据
     queryset = models.BookInfo.objects.all()
     # serializer_class: 设置序列化的类
     serializer_class = BookinfoSeralizer
     # pagination_class : 设置分页的类
     pagination_class = MyPageNumberPagination
   """
   第四个:ModelViewSet视图的使用
   ModelViewSet继承自istModelMixin,CreateModelMixin,
   RetrieveModelMixin,DestroyModelMixin,UpdateModelMixin视图
   如果要实现最基本的增删改查功能,就直接继承自ModelViewSet
   """
   from rest_framework.viewsets import ModelViewSet
   class BookView(ModelViewSet):
     # queryset: 设置获取的数据
     queryset = models.BookInfo.objects.all()
     # serializer_class: 设置序列化的类
     serializer_class = BookinfoSeralizer
     # pagination_class : 设置分页的类
     pagination_class = MyPageNumberPagination
   """
   视图使用小总结
     只想实现简单的增删改查
       ModelViewSet
     只想增
       CreateModelMixin,GenericViewSet
     只想增删改
       CreateModelMixin,DestroyModelMixin,UpdateModelMixin,GenericViewSet
     如果视图中的业务逻辑复杂,以上都不能满足的时候,直接使用
       APIView
  #自动路由配置
  """
    from django.conf.urls import url,include
    from api import views
    from rest_framework import routers
    
    router = routers.DefaultRouter()
    router.register(r"bookpage",views.BookView,base_name='bookpage')
    
    
    urlpatterns = [
     url(r'v1/',include(router.urls)),
    ]
  """
    
 自动路由会生成四个接口
 ^api/ v1/ ^bookpage/$ [name='bookpage-list']
 ^api/ v1/ ^bookpage\.(?P<format>[a-z0-9]+)/?$ [name='bookpage-list']
 ^api/ v1/ ^bookpage/(?P<pk>[^/.]+)/$ [name='bookpage-detail']
 ^api/ v1/ ^bookpage/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='bookpage-detail']

频率限制节流

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
节流:
  自定义节流类
  """
  VISIT_RECORD = {}
  class VisitThrottle(object):
    def __init__(self):
      self.history = None
    def allow_request(self,request,view):
      #实现节流的逻辑
      #基于ip做节流
      # #获取用户访问的IP地址
      # ip_address = request._request.META.get('REMOTE_ADDR')
      ctime = time.time()
      # if ip_address not in VISIT_RECORD:
      #   #第一次访问的时候将访问的时间存储在字典中(ip地址为Key,访问的时间为value值)
      #   VISIT_RECORD[ip_address] = [ctime,]
      #
      # #第二次访问的时候取出访问的历史记录
      # history = VISIT_RECORD[ip_address]
      # 基于用户的节流
      username = request.user.username
      if username not in VISIT_RECORD:
        VISIT_RECORD[username] = [ctime, ]
      history = VISIT_RECORD[username]
      self.history = history
      while history and history[-1] < ctime - 10:
        #如果访问的时间记录超过60秒,就把超过60秒的时间记录移除
        history.pop()
      if len(history) < 6:
        history.insert(0,ctime)
        return True
      return False
    def wait(self):
      #一旦用户访问次数到达阀值,显示用户需要等待的时间
      ctime = time.time()
            #09:54:30  09:54:28
      return 10 - (ctime - self.history[-1])
  """
 
  局部使用
  """
    class OrderView(APIView):
      # throttle_classes设置节流类
      throttle_classes = [VisitThrottle,]
  """
      
  全局设置
  """
  REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES':['unitls.throttle.VisitThrottle'],
  }
  """
  
  使用DRF内置的限频类
  """
  from rest_framework.throttling import SimpleRateThrottle
  
  #推荐使用这种
  class VisitThrottle(SimpleRateThrottle):
    #没有登录用户,每分钟访问10次
    scope = 'logined'
    def get_cache_key(self, request, view):
    return request.user.username
  """
 
  全局设置
  """
  REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_RATES':{
      'unlogin':'10/m',
      'logined':'3/m',
    },
    'DEFAULT_THROTTLE_CLASSES':['unitls.throttle.VisitThrottle'],
  }
  """

版本控制

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  自定义版本控制类
"""
  class ParmasVersion(object):
    def determine_version(self, request, *args, **kwargs):
      version = request.query_params.get('version')
      return version
"""
 
使用(局部)
"""
  class VersionView(APIView):
    #设置获取版本的类
    versioning_class = ParmasVersion
"""
 
全局设置
"""
   'DEFAULT_VERSIONING_CLASS':'unitls.version.ParmasVersion',
"""
 
使用 DRF内置的版本控制类QueryParameterVersioning(局部)
"""
  from rest_framework.versioning import QueryParameterVersioning
  class VersionView(APIView):
    #设置获取版本的类
    versioning_class = QueryParameterVersioning
"""
 
设置文件中的配置信息
"""
  REST_FRAMEWORK = {
    'VERSION_PARAM':'version',
    'DEFAULT_VERSION':'v1',
    'ALLOWED_VERSIONS':['v1','v2'],
  }
"""
 
全局设置
"""
  REST_FRAMEWORK = {
    'VERSION_PARAM':'version',
    'DEFAULT_VERSION':'v1',
    'ALLOWED_VERSIONS':['v1','v2'],
    'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.QueryParameterVersioning',
  }
"""
 
 
使用 DRF内置的版本控制类URLPathVersioning(局部)
"""
  from rest_framework.versioning import URLPathVersioning
  class VersionView(APIView):
    #设置获取版本的类
    versioning_class = URLPathVersioning
  """
 
设置文件中的配置信息
"""
  REST_FRAMEWORK = {
    'VERSION_PARAM':'version',
    'DEFAULT_VERSION':'v1',
    'ALLOWED_VERSIONS':['v1','v2'],
  }
  """
 
全局设置
"""
  REST_FRAMEWORK = {
    'VERSION_PARAM':'version',
    'DEFAULT_VERSION':'v1',
    'ALLOWED_VERSIONS':['v1','v2'],
    'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning',
  }
"""
 
如果使用URLPathVersioning,路由格式如下
"""
  url(r"^(?P<version>[v1|v2]+)/version/",VersionView.as_view(),name='vvvv')
"""
 
#使用 DRF内置的版本控制类URLPathVersioning 反向生成url地址
"""
  #反向生成url地址 reverse
  obj = request.versioning_scheme
  url1 = obj.reverse(viewname='orders',request=request)
  
  #使用django的reverse方法反响生成url地址
  from django.urls import reverse
  url2 = reverse(viewname='orders',kwargs={'version':'v2'})
"""

解析器

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
因为开发人员post请求上传数据时,传递的数据类型不同,我们可能在request._request.POST中获取不到数据
 
  case1: Content-Type : application/x-www-form-urlencoded
  服务端接收到的post请求的数据格式:username=xxxxx&age=18&sex=
  我们就可以在request._request.POST中获取到数据
  """
    class UserInfoView(APIView):
      def post(self,request,*args,**kwargs):
        username = request._request.POST.get('username')
        age = request._request.POST.get('age')
        sex = request._request.POST.get('sex')
  """
 
  case2:Content-Type:application/json
  服务端接收到的post请求的数据格式就是json数据:{"username":"xxxx","age":"18","sex":"男"}
  在request._request.POST中就获取不到数据,但是在request.body中可以拿到
  """
    class UserInfoView(APIView):
      def post(self,request,*args,**kwargs):
        import json
        data = json.loads(request.body.decode('utf8'))
        print(data)
  """
 
  DRF内置的解析器FormParser,JSONParser
  使用(局部):
  """
    from rest_framework.parsers import FormParser,JSONParser
    class UserInfoView(APIView):
      parser_classes = [FormParser,JSONParser]
      
      #这时DRF 内部代码会根据request.Content-Type和解析器支持的media_type比较
      从而选择对应的解析器
      
      def post(self,request,*args,**kwargs):
        # 如果使用JSONParser、FormParser解析数据的话
        data = request.data
        print(data)
      
  """

渲染器

?
1
2
3
4
5
6
7
8
渲染器
 INSTALLED_APPS = [
          'rest_framework',
          ]
 from rest_framework.renderers import BrowsableAPIRenderer,JSONRenderer,AdminRenderer
 class BookView(ModelViewSet):
   # 设置渲染器类型
   renderer_classes = [JSONRenderer]

序列化

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
Django的序列化
 """
 #django序例化方式一
 books = models.BookInfo.objects.all().values('id','bookname')
 books = list(books)
 print(type(books), books)
 self.ret['books'] = books
 #django序例化方式二
 books = models.BookInfo.objects.all()
 books = [model_to_dict(item) for item in books]
 self.ret['books'] = books
 """
 
 DRF 序列化
 第一种:继承自serializers.Serializer
 """
    class BookDetailSerializer(serializers.Serializer):
        # 正常的字段序列化
        id = serializers.IntegerField()
        bookname = serializers.CharField()
        author = serializers.CharField()
        category = serializers.IntegerField()
        bookdesc = serializers.CharField()
        
        
        # 获取枚举类型的文本是 source=get_字段名_display
        status = serializers.CharField(
          source='get_status_display'
        )
        categoryname = serializers.CharField(
          source='get_category_display'
        )
        
        # 自定义方法获取字段
        chpaters = serializers.SerializerMethodField()
        #序列化时可以自定义方法获取字段
        def get_chpaters(self,row):
          """ row - > bookinfo """
            chpaters = models.ChpaterInfo.objects.filter(book=row)
            ser = ChpaterSerializer(instance=chpaters,many=True,
                        context=self.context
                        )
            return ser.data
 """
  序列化时生成url
 """
   url = serializers.HyperlinkedIdentityField(
   view_name='chpaterdetail', lookup_field='id',
   lookup_url_kwarg='pk',
   )
 """
 注意:如果序列化类中使用HyperlinkedIdentityField生成url,那我们在序例化时添加context={'request': request}
 """
   ser = BookDetailSerializer(
   instance=obj,many=False,
   context={'request': request}
   )
 """
 
 如果出现关联关系时,获取model对像的某一个字段
 """
   bookname = serializers.CharField(source='book.bookname')
 """
 
 第二种继承自:serializers.ModelSerializer
 """
 class ChpaterDetailSerializer(serializers.ModelSerializer):
   #使用ModelSerializer进行章节详情的序列化
   bookname = serializers.CharField(source='book.bookname')
   class Meta:
     model = models.ChpaterInfo
     #fields = "__all__"
     fields = ['id','bookname']
 """
 
 DRF (序列化时)自定义方法获取数据
 """
   book = serializers.SerializerMethodField()
 """
 """
    def get_book(self,row):
      """ row - > UserInfo"""
        print('======',row.book.all())
        ser = UsersBooksSerializer(
          instance=row.book.all(),
          many=True
        )
     
        return ser.data
 """
 
 DRF depth深度的使用
 # depth会根据关联的数据不停的深入将数据获取出来(最多不超过10层)
 # depth = 1
 """
 class UsersSerializer(serializers.ModelSerializer):
   class Meta:
     model = models.UserInfo
     fields = "__all__"
     #depth会根据关联的数据不停的深入将数据获取出来(最多不超过10层)
     depth = 1
 """
 
 DRF序列化的验证功能
 """
 class UsersSerializer(serializers.ModelSerializer):
   #自定义验证错误的信息
   username = serializers.CharField(error_messages={'required':'用户名不能为空'})
   class Meta:
     model = models.UserInfo
     fields = "__all__"
 """
 
 """
 class UsersView(APIView):
   def post(self,request,*args,**kwargs):
   """DRF 序列化自带验证功能"""
     data = request.data
     #print(data)
     ser = UsersSerializer(data=data)
     if ser.is_valid(): # ser.is_valid()y验证数据的有效性
       print('验证后的数据',ser.validated_data)
       #验证后的数据正确后,保存数据至数据库
       ser.save()
     else:
       #上传数据不符合规范时ser.errors,返回错误详细
       print(ser.errors)
     return Response(data)
 """
 
 自定义字段验证规则
 """
   class UsersInfoSerializer(serializers.ModelSerializer):
   username = serializers.CharField(error_messages={'required':'用户名不能为空'})
     class Meta:
       model = models.UserInfo
       fields = "__all__"
     
     # 用户名中必须包含老王两个字,不包含则认为名字无效
     def validate_username(self,validated_value):
       print(validated_value)
       from rest_framework.exceptions import ValidationError
       if '老王' not in validated_value:
       #验证不通过,抛出异常
         raise ValidationError('用户名不合法')
       #验证通过,返回数据
       return validated_value
 """

以上就是python drf各类组件的用法和作用的详细内容,更多关于python drf组件的资料请关注服务器之家其它相关文章!

原文链接:https://www.cnblogs.com/x945669/p/13280713.html

延伸 · 阅读

精彩推荐