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