rest_framework
1.编程:数据结构和算法的结合
2.restful规范
定义:url唯一定位资源,http请求方式区分用户行为
(1)接口设计规范
(2)返回数据规范
(3)错误消息规范
4.restframework下的APIView的请求流程和原码
下载:pip install djangorestframework
引入:from rest_framework import APIView
APIView的原码:
5.POSTMAN工具的使用
能够发各种方式的请求并对请求头的数据进行修改且对结果进行格式化的工具
6.DRF解析器(parser)的请求流程和原码
解析器:Django只能解析urlencoded格式的数据,通过解析器 可以解析各种数据类型(json)的数据
(1)使用方式
导入模块
1 from rest_framework.views import APIView
(2)继承
(3)
(4)使用
原码:
APIView中的
二.序列化组件
0.原始序列化方法
model对象=>字典
from django.forms.models import model_to_dict
model_to_dict方法:将model对象转换成字典
0.djaogo的自带的序列化方法
from django.core import serializers
ret=serializers.serialize("json",queryset)
得到的ret就是序列化后的结果
rest_framework的serializer使用方法(五个接口)
1.get接口设计(查看多条数据)
(1)Serializer,类似于Form
1 #1.导入模块 2 from rest_framework.views import APIView 3 from rest_framework import serializers 4 #使返回的数据能够格式化 5 #浏览器上也能够使用rest_framework组件 6 #***前提是settings中的INSTALLED_APPS要配置该组件*** 7 from rest_framework.response import Response 8 9 from django.shortcuts import HttpResponse 10 from app01.models import * 11 12 #2.写一个类继承serializers.Serializer 13 class BookSerializer(serializers.Serializer): 14 title=serializers.CharField(max_length=32) 15 price=serializers.CharField(max_length=32) 16 #对于一对多的字段,用source来决定返回给前端的内容 17 publish=serializers.CharField(source="publish.name") 18 #对于多对多的字段,用钩子函数来编辑返回给前端的内容 19 authors=serializers.SerializerMethodField() 20 #钩子函数的名字是get+字段的名字 21 def get_authors(self,book_obj): 22 s="" 23 for obj in book_obj.authors.all(): 24 s=s+obj.name 25 return s 26 27 class BookView(APIView): 28 def get(self,request): 29 book_list=Book.objects.all() 30 #多个对象时 31 #many为True表示多个对象,默认为false,位false时可以省略不写 32 bs=BookSerializer(book_list,many=True) 33 #单个对象时 34 #bs=BookSerializer(book_obj) 35 return Response(bs.data) # 返回的是[{},{}]的形式
由于使用的是Response返回的数据,访问该路径时,能够得到rest_framework组件为我们提供的页面
在访问的路径后加上?format=json,得到的是数据部分
(2)ModelSerializer,类似于ModelForm
1 #1.导入模块 2 from rest_framework.views import APIView 3 from rest_framework import serializers 4 #使返回的数据能够格式化 5 #浏览器上也能够使用rest_framework组件 6 #***前提是settings中的INSTALLED_APPS要配置该组件*** 7 from rest_framework.response import Response 8 9 from django.shortcuts import HttpResponse 10 from app01.models import * 11 12 #2.写一个类继承serializers.ModelSerializer 13 class BookModelSerializer(serializers.ModelSerializer): 14 class Meta: 15 model=Book 16 fields="__all__" 17 #自定义的字段 18 publish=serializers.CharField(source="publish.name") 19 authors=serializers.SerializerMethodField() 20 def get_authors(self,book_obj): 21 s="" 22 for obj in book_obj.authors.all(): 23 s=s+obj.name 24 return s 25 26 class BookView(APIView): 27 def get(self,request): 28 book_list=Book.objects.all() 29 #多个对象时 30 #many为True表示多个对象,默认为false,位false时可以省略不写 31 bs=BookModelSerializer(book_list,many=True) 32 #单个对象时 33 #bs=BookSerializer(book_obj) 34 return Response(bs.data) # 返回的是[{},{}]的形式
访问时得到的页面
1 from django.shortcuts import HttpResponse 2 from app01.models import * 3 from rest_framework.views import APIView 4 from rest_framework import serializers 5 #使返回的数据能够格式化 6 #浏览器上也能够使用rest_framework组件 7 #前提是settings中的INSTALLED_APPS要配置该组件 8 from rest_framework.response import Response 9 10 #1.编写继承ModelSerializer的类 11 class BookModelSerializer(serializers.ModelSerializer): 12 class Meta: 13 model=Book 14 fields="__all__" 15 publish=serializers.CharField(source="publish.pk") 16 # authors=serializers.SerializerMethodField() 17 18 def get_authors(self,book_obj): 19 s="" 20 for obj in book_obj.authors.all(): 21 s=s+obj.name 22 return s 23 #2.对于一对多的字段,ModelSerializer中的create方法不支持source,重写create方法 24 def create(self,validated_data): 25 book_obj=Book.objects.create(title=validated_data["title"],price=validated_data["price"],publish_id=validated_data["publish"]["pk"]) 26 book_obj.authors.add(*validated_data["authors"]) 27 return book_obj 28 29 class BookView(APIView): 30 def post(self,request): 31 bs=BookModelSerializer(data=request.data) 32 #3.通过实例对象的is_valid()方法,对请求数据的合法性进行校验,有instance就是update,没有就是create 33 if bs.is_valid(): 34 #4.调用save()方法,将数据插入数据库 35 #会执行create方法 36 bs.save() 37 return Response(bs.data) 38 else: 39 #5.数据不合格返回错误信息 40 return Response(bs.errors)
3.单条数据接口(查询单个数据)
(1)url设计
1 urlpatterns = [ 2 path('admin/', admin.site.urls), 3 re_path('book/$', views.BookView.as_view()), 4 re_path('book/(\d+)/$', views.BookDetailView.as_view()), 5 ]
(2)视图设计
1 from django.shortcuts import HttpResponse 2 from app01.models import * 3 from rest_framework.views import APIView 4 from rest_framework import serializers 5 from rest_framework.response import Response 6 7 class BookModelSerializer(serializers.ModelSerializer): 8 class Meta: 9 model=Book 10 fields="__all__" 11 publish=serializers.CharField(source="publish.pk") 12 # authors=serializers.SerializerMethodField() 13 14 def get_authors(self,book_obj): 15 s="" 16 for obj in book_obj.authors.all(): 17 s=s+obj.name 18 return s 19 def create(self,validated_data): 20 book_obj=Book.objects.create(title=validated_data["title"],price=validated_data["price"],publish_id=validated_data["publish"]["pk"]) 21 book_obj.authors.add(*validated_data["authors"]) 22 return book_obj 23 24 class BookDetailView(APIView): 25 def get(self,request,id): 26 book=Book.objects.filter(pk=id).first() 27 bs=BookModelSerializer(book) 28 return Response(bs.data)
(3)返回数据
1 from django.shortcuts import HttpResponse 2 from app01.models import * 3 from rest_framework.views import APIView 4 from rest_framework import serializers 5 from rest_framework.response import Response 6 7 class BookModelSerializer(serializers.ModelSerializer): 8 class Meta: 9 model=Book 10 fields="__all__" 11 12 class BookDetailView(APIView): 13 def put(self,request,id): 14 book = Book.objects.filter(pk=id).first() 15 bs=BookModelSerializer(book,data=request.data) 16 if bs.is_valid(): 17 #此时执行的不是create方法,是update方法 18 bs.save() 19 return Response(bs.data) 20 else: 21 return Response(bs.errors)
1 from django.shortcuts import HttpResponse 2 from app01.models import * 3 from rest_framework.views import APIView 4 from rest_framework import serializers 5 from rest_framework.response import Response 6 7 class BookModelSerializer(serializers.ModelSerializer): 8 class Meta: 9 model=Book 10 fields="__all__" 11 12 class BookDetailView(APIView): 13 def delete(self,request,id): 14 Book.objects.filter(pk=id).delete() 15 return Response()
超链接API:Hyperlinked
实现效果:
建立向Book表的BookView,BookDetailView一样的Publish表的两个视图类
1 class PublishView(APIView): 2 def get(self,request): 3 book_list=Publish.objects.all() 4 print(book_list) 5 bs=PublishModelSerializer(book_list,many=True) 6 print(bs) 7 print(bs.data) 8 return Response(bs.data) # [{},{}]的形式 9 def post(self,request): 10 print(request.data) bs=PublishModelSerializer(data=request.data) 11 if bs.is_valid(): 12 #会执行create方法 13 print(111) 14 bs.save() 15 print(bs.data) 16 return Response(bs.data) 17 else: 18 return Response(bs.errors) 19 class PublishDetailView(APIView): 20 def get(self,request,id): 21 book=Publish.objects.filter(pk=id).first() 22 bs=PublishModelSerializer(book) 23 print(book) 24 print(bs) 25 print('-------',bs.data) 26 return Response(bs.data) 27 28 def put(self,request,id): 29 book = Publish.objects.filter(pk=id).first() 30 bs=PublishModelSerializer(book,data=request.data) 31 if bs.is_valid(): 32 bs.save() 33 return Response(bs.data) 34 else: 35 return Response(bs.errors) 36 37 def delete(self,request,id): 38 Publish.objects.filter(pk=id).delete() 39 return Response()
视图类中需要的PublishModelSerializer
1 class PublishModelSerializer(serializers.ModelSerializer): 2 class Meta: 3 model=Publish 4 fields="__all__"
修改访问BookView时的publish的显示方式
1 class BookModelSerializer(serializers.ModelSerializer): 2 class Meta: 3 model=Book 4 fields="__all__" 5 publish=serializers.HyperlinkedIdentityField( 6 view_name="publish_detail",#路径的别名 7 lookup_field="publish_id", 8 lookup_url_kwarg="id"#路径中用到的动态匹配的数据 9 )
设置BookModelSerializer需要的view_name,lookup_url_kwarg
1 urlpatterns = [ 2 path('admin/', admin.site.urls), 3 # path('publish/', views.PublishView.as_view()), 4 path('publishnew/', views.PublishnNewView.as_view(),name="publishnew"), 5 re_path('book/$', views.BookView.as_view(),name="book"), 6 re_path('publish/$', views.PublishView.as_view(),name="publish"), 7 re_path('book/(\d+)/$', views.BookDetailView.as_view(),name="bookdetail"), 8 re_path('publish/(?P<id>\d+)/$', views.PublishDetailView.as_view(),name="publish_detail"), 9 ]
用了Hyperlinked,以后调用时,都要加上context={'request': request}
三.视图组件
1.mixin类编写视图
1 CreateModelMixin 添加 2 DestroyModelMixin 删除 3 ListModelMixin 查多个 4 RetrieveModelMixin 查单个 5 UpdateModelMixin 更新
ListModelMixin部分原码
1 class ListModelMixin(object): 2 """ 3 List a queryset. 4 """ 5 def list(self, request, *args, **kwargs): 6 #获取queryset 7 queryset = self.filter_queryset(self.get_queryset()) 8 9 page = self.paginate_queryset(queryset) 10 if page is not None: 11 serializer = self.get_serializer(page, many=True) 12 return self.get_paginated_response(serializer.data) 13 #序列化 14 serializer = self.get_serializer(queryset, many=True) 15 #返回.data数据 16 return Response(serializer.data)
CreateModelMixin部分原码
1 class ListModelMixin(object): 2 """ 3 List a queryset. 4 """ 5 def list(self, request, *args, **kwargs): 6 #获取queryset 7 queryset = self.filter_queryset(self.get_queryset()) 8 9 page = self.paginate_queryset(queryset) 10 if page is not None: 11 serializer = self.get_serializer(page, many=True) 12 return self.get_paginated_response(serializer.data) 13 #序列化 14 serializer = self.get_serializer(queryset, many=True) 15 #返回.data数据 16 return Response(serializer.data)
CreateModelMixin部分原码
1 class CreateModelMixin(object): 2 """ 3 Create a model instance. 4 """ 5 def create(self, request, *args, **kwargs): 6 #获取ModelSerializer的实例对象 7 serializer = self.get_serializer(data=request.data) 8 #判断是否合法,成功了继续走,错误了抛错 9 serializer.is_valid(raise_exception=True) 10 #合法后执行save方法 11 self.perform_create(serializer) 12 headers = self.get_success_headers(serializer.data) 13 return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) 14 15 def perform_create(self, serializer): 16 serializer.save() 17 18 def get_success_headers(self, data): 19 try: 20 return {'Location': str(data[api_settings.URL_FIELD_NAME])} 21 except (TypeError, KeyError): 22 return {}
使用
在urls.py中
1 urlpatterns = [ 2 path('admin/', admin.site.urls), 3 re_path('author/$', views.AuthorView.as_view(),name="author"), 4 #***此处正则表达式的有名分组一定要命名为pk*** 5 re_path('author/(?P<pk>\d+)/$', views.AuthorDetailView.as_view(),name="author_detail"), 6 ]
在视图中
1 #1.导入需要的类 2 from rest_framework import mixins 3 from rest_framework import generics 4 5 #GenericAPIView继承了APIView 6 #定义的类除了要继承mixins下的类以外,还要继承GenericAPIView类 7 class AuthorView(mixins.ListModelMixin,mixins.CreateModelMixin,generics.GenericAPIView): 8 #以下两个配置信息的名字是固定的 9 #queryset此次表示处理的数据 10 queryset=Author.objects.all() 11 #serializers表示用到的序列化组件 12 serializer_class=AuthorModelSerializer 13 def get(self, request, *args, **kwargs): 14 #ListModelMixin类中的方法 15 return self.list(self, request, *args, **kwargs) 16 def post(self, request, *args, **kwargs): 17 #CreateModelMixin中的方法 18 return self.create(self, request, *args, **kwargs) 19 20 class AuthorDetailView(mixins.RetrieveModelMixin,mixins.DestroyModelMixin,mixins.UpdateModelMixin,generics.GenericAPIView): 21 queryset = Author.objects.all() 22 serializer_class = AuthorModelSerializer 23 def get(self, request,pk, *args, **kwargs): 24 return self.retrieve(self, request,pk, *args, **kwargs) 25 def put(self, request,id, *args, **kwargs): 26 return self.update(self, request,id, *args, **kwargs) 27 def delete(self, request,id, *args, **kwargs): 28 return self.destroy(self, request,id, *args, **kwargs)
get请求得到的数据
1 [ 2 { 3 "nid": 1, 4 "name": "徐志摩", 5 "age": 25 6 }, 7 { 8 "nid": 2, 9 "name": "鲁迅", 10 "age": 25 11 } 12 ]
2.使用通用的基于类的视图
ListCreateAPIView原码部分
1 ##ListCreateAPIView固定继承了mixins.ListModelMixin,mixins.CreateModelMixin,GenericAPIView 2 class ListCreateAPIView(mixins.ListModelMixin, 3 mixins.CreateModelMixin, 4 GenericAPIView): 5 #贴心到连get和post方法都写了 6 def get(self, request, *args, **kwargs): 7 return self.list(request, *args, **kwargs) 8 9 def post(self, request, *args, **kwargs): 10 return self.create(request, *args, **kwargs)
RetrieveUpdateDestroyAPIView原码部分(与ListCreateAPIView原理相同)
1 class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin, 2 mixins.UpdateModelMixin, 3 mixins.DestroyModelMixin, 4 GenericAPIView): 5 6 def get(self, request, *args, **kwargs): 7 return self.retrieve(request, *args, **kwargs) 8 9 def put(self, request, *args, **kwargs): 10 return self.update(request, *args, **kwargs) 11 12 def patch(self, request, *args, **kwargs): 13 return self.partial_update(request, *args, **kwargs) 14 15 def delete(self, request, *args, **kwargs): 16 return self.destroy(request, *args, **kwargs)
使用
在urls.py中
1 urlpatterns = [ 2 path('admin/', admin.site.urls), 3 re_path('author/$', views.AuthorView.as_view(),name="author"), 4 #***此处正则表达式的有名分组一定要命名为pk*** 5 re_path('author/(?P<pk>\d+)/$', views.AuthorDetailView.as_view(),name="author_detail"), 6 ]
在视图中
1 from rest_framework import generics 2 3 class AuthorView(generics.ListCreateAPIView): 4 queryset=Author.objects.all() 5 serializer_class=AuthorModelSerializer 6 7 class AuthorDetailView(generics.RetrieveUpdateDestroyAPIView): 8 queryset = Author.objects.all() 9 serializer_class = AuthorModelSerializer
3.viewsets.ModelViewSet
使用
在urls.py中
1 urlpatterns = [ 2 path('admin/', admin.site.urls), 3 #利用as_view的参数,规定什么请求方式用什么方法处理 4 re_path(r'^books/$', views.AuthorViewSet.as_view({"get": "list", "post": "create"}), name="book_list"), 5 re_path(r'^books/(?P<pk>\d+)$', views.AuthorViewSet.as_view({ 6 'get': 'retrieve', 7 'put': 'update', 8 'patch': 'partial_update', 9 'delete': 'destroy' 10 }), name="book_detail"), 11 ]
在视图中
1 from rest_framework import viewsets 2 class AuthorViewSet(viewsets.ModelViewSet): 3 queryset = Book.objects.all() 4 serializer_class = AuthorModelSerializer
四.认证组件
1.使用方式
单个认证
(1)定义一个认证类
1 class UserAuth(): 2 #此方法原码中会用到,一定要写 3 def authenticate_header(self,request): 4 pass 5 def authenticate(self,request): 6 token=request.GET.get("token") 7 token_obj = UserToken.objects.filter(token=token).first() 8 if not token_obj: 9 raise APIException("验证失败!") 10 return (token_obj.user, token_obj)
或者用BaseAuthentication类来代替authenticate_header方法
1 from rest_framework.authentication import BaseAuthentication 2 class UserAuth(BaseAuthentication): 3 def authenticate(self,request): 4 token=request.GET.get("token") 5 token_obj = UserToken.objects.filter(token=token).first() 6 if not token_obj: 7 raise APIException("验证失败!") 8 return (token_obj.user, token_obj)
(2)在需要认证的数据接口里面指定认证类
1 class AuthorViewSet(viewsets.ModelViewSet): 2 ***authentication_classes = [UserAuth,]*** 3 queryset = Author.objects.all() 4 serializer_class = AuthorModelSerializer
(3)前提:要在登录时注入token
1 def get_random_str(): 2 import uuid 3 random_str=str(uuid.uuid4()).replace("-","") 4 return random_str 5 6 class LoginView(APIView): 7 def post(self,request): 8 user_name=request.data.get("user_name") 9 password=request.data.get("password") 10 user_obj=User.objects.filter(user_name=user_name,password=password).first() 11 res={} 12 if not user_obj: 13 res["state"]=1001 14 res["meg"]='用户名或秘密错误' 15 else: 16 token=get_random_str() 17 print(token) 18 UserToken.objects.update_or_create(user=user_obj, defaults={"token": token}) 19 res["state"]=1000 20 res["meg"]='登录成功' 21 return JsonResponse(res)
全局认证
(1)将UserAuth单放在一个文件中
utiles中
1 from app01.models import * 2 from rest_framework.exceptions import APIException 3 class UserAuth(): 4 def authenticate_header(self,request): 5 pass 6 def authenticate(self,request): 7 token=request.GET.get("token") 8 token_obj = UserToken.objects.filter(token=token).first() 9 if not token_obj: 10 raise APIException("验证失败!") 11 return (token_obj.user, token_obj)
(2)在配置文件中添加配置
1 REST_FRAMEWORK={ 2 "DEFAULT_AUTHENTICATION_CLASSES":("app01.utiles.UserAuth",) 3 }
class APIView(View):
1 #***1执行as_view方法 2 def as_view(cls, **initkwargs): 3 if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet): 4 def force_evaluation(): 5 raise RuntimeError( 6 'Do not evaluate the `.queryset` attribute directly, ' 7 'as the result will be cached and reused between requests. ' 8 'Use `.all()` or call `.get_queryset()` instead.' 9 ) 10 cls.queryset._fetch_all = force_evaluation 11 #***2.继承父类的as_view方法并执行 12 view = super(APIView, cls).as_view(**initkwargs) 13 view.cls = cls 14 view.initkwargs = initkwargs 15 return csrf_exempt(view) 16 17 ########################################################### 18 19 #***3.续 20 def dispatch(self, request, *args, **kwargs): 21 """ 22 `.dispatch()` is pretty much the same as Django's regular dispatch, 23 but with extra hooks for startup, finalize, and exception handling. 24 """ 25 self.args = args 26 self.kwargs = kwargs 27 #***4.执行initialize_request方法 28 request = self.initialize_request(request, *args, **kwargs) 29 self.request = request 30 self.headers = self.default_response_headers # deprecate? 31 32 try: 33 #***8.执行inital方法 34 self.initial(request, *args, **kwargs) 35 36 # Get the appropriate handler method 37 if request.method.lower() in self.http_method_names: 38 handler = getattr(self, request.method.lower(), 39 self.http_method_not_allowed) 40 else: 41 handler = self.http_method_not_allowed 42 43 response = handler(request, *args, **kwargs) 44 45 except Exception as exc: 46 response = self.handle_exception(exc) 47 48 self.response = self.finalize_response(request, response, *args, **kwargs) 49 return self.response 50 51 ########################################################### 52 53 #***4.续 54 def initialize_request(self, request, *args, **kwargs): 55 """ 56 Returns the initial request object. 57 """ 58 parser_context = self.get_parser_context(request) 59 #***5.实例化Request对象 60 return Request( 61 request, 62 parsers=self.get_parsers(), 63 #***6.执行get_authenticators方法 64 authenticators=self.get_authenticators(), 65 negotiator=self.get_content_negotiator(), 66 parser_context=parser_context 67 ) 68 69 ########################################################### 70 #***6.续 71 def get_authenticators(self): 72 #***7.authentication_classes为自定义的类中的字段:[UserAuth,] 73 return [auth() for auth in self.authentication_classes] 74 75 ########################################################### 76 #***8.续 77 def initial(self, request, *args, **kwargs): 78 self.format_kwarg = self.get_format_suffix(**kwargs) 79 neg = self.perform_content_negotiation(request) 80 request.accepted_renderer, request.accepted_media_type = neg 81 82 version, scheme = self.determine_version(request, *args, **kwargs) 83 request.version, request.versioning_scheme = version, scheme 84 #***9.用户认证方法 85 self.perform_authentication(request) 86 self.check_permissions(request) 87 self.check_throttles(request) 88 89 ########################################################### 90 91 #***9.续 92 def perform_authentication(self, request): 93 #***10.执行Request类下的user方法 94 request.user
class View:
1 def as_view(cls, **initkwargs): 2 3 for key in initkwargs: 4 if key in cls.http_method_names: 5 raise TypeError("You tried to pass in the %s method name as a " 6 "keyword argument to %s(). Don't do that." 7 % (key, cls.__name__)) 8 if not hasattr(cls, key): 9 raise TypeError("%s() received an invalid keyword %r. as_view " 10 "only accepts arguments that are already " 11 "attributes of the class." % (cls.__name__, key)) 12 13 def view(request, *args, **kwargs): 14 self = cls(**initkwargs) 15 if hasattr(self, 'get') and not hasattr(self, 'head'): 16 self.head = self.get 17 self.request = request 18 self.args = args 19 self.kwargs = kwargs 20 #***3.执行APIView中的dispatch方法 21 return self.dispatch(request, *args, **kwargs) 22 view.view_class = cls 23 view.view_initkwargs = initkwargs 24 update_wrapper(view, cls, updated=()) 25 update_wrapper(view, cls.dispatch, assigned=()) 26 return view
自定义
1 #***7.续 2 class AuthorViewSet(viewsets.ModelViewSet): 3 authentication_classes = [UserAuth,] 4 queryset = Author.objects.all() 5 serializer_class = AuthorModelSerializer
Request
1 #***10.续 2 def user(self): 3 if not hasattr(self, '_user'): 4 with wrap_attributeerrors(): 5 #***11.执行_authenticate方法 6 self._authenticate() 7 #***15.返回14步骤的当前登录对象 8 return self._user 9 10 ############################################################# 11 12 #***11.续 13 def _authenticate(self): 14 #***12.self.authenticators为7步骤的结果[UserAuth(),] 15 for authenticator in self.authenticators: 16 try: 17 #***13.执行自定义的认证类下的authenticate方法 18 user_auth_tuple = authenticator.authenticate(self) 19 #***14.续 20 #如果用户的token值错误抛错,在此抛错 21 except exceptions.APIException: 22 self._not_authenticated() 23 raise 24 25 if user_auth_tuple is not None: 26 self._authenticator = authenticator 27 #如果用户的token值正确, self.user为当前登录对象 28 self.user, self.auth = user_auth_tuple 29 return 30 31 self._not_authenticated()
class UserAuth():
1 def authenticate_header(self,request): 2 pass 3 #***13.续 4 def authenticate(self,request): 5 token=request.GET.get("token") 6 token_obj = UserToken.objects.filter(token=token).first() 7 #***14.分情况讨论 8 if not token_obj: 9 #如果用户的token值错误,抛错 10 raise APIException("验证失败!") 11 #如果用户带有正确的token值 12 return (token_obj.user, token_obj)
1.一次性从前端获取多条数据
2.给 name属性赋值,就会执行 第二个方法
1.使用方式
单个权限
(1)定义权限类
1 class UserPerms(): 2 #方法名称一定叫has_permission 3 #自定义错误信息 4 def has_permission(self,request,view): 5 if request.user.user_type == 3: 6 return True 7 else: 8 return False
(2)指定权限验证类
1 class AuthorViewSet(viewsets.ModelViewSet): 2 authentication_classes = [UserAuth,] 3 #使用 方式与认证相同 4 permission_classes = [UserPerms,] 5 queryset = Author.objects.all() 6 serializer_class = AuthorModelSerializer
可以指定多个认证类,如果返回数据,应在最后一个类中返回数据
(3)前提也是登录时要注入token
全局权限
1 REST_FRAMEWORK={ 2 "DEFAULT_PERMISSION_CLASSES":["app01.utiles.UserPerms",] 3 }
2.原码剖析
从APIView的dispatch方法开始剖析
APIView
1 #***1.执行dispatch方法def dispatch(self, request, *args, **kwargs): 2 3 self.args = args 4 self.kwargs = kwargs 5 request = self.initialize_request(request, *args, **kwargs) 6 self.request = request 7 self.headers = self.default_response_headers # deprecate? 8 9 try: 10 #***2.执行initial方法(有续) 11 self.initial(request, *args, **kwargs) 12 13 # Get the appropriate handler method 14 if request.method.lower() in self.http_method_names: 15 handler = getattr(self, request.method.lower(), 16 self.http_method_not_allowed) 17 else: 18 handler = self.http_method_not_allowed 19 20 response = handler(request, *args, **kwargs) 21 22 except Exception as exc: 23 response = self.handle_exception(exc) 24 25 self.response = self.finalize_response(request, response, *args, **kwargs) 26 return self.response 27 28 ##############################################################333# 29 30 #***2.续 31 def initial(self, request, *args, **kwargs): 32 33 self.format_kwarg = self.get_format_suffix(**kwargs) 34 35 # Perform content negotiation and store the accepted info on the request 36 neg = self.perform_content_negotiation(request) 37 request.accepted_renderer, request.accepted_media_type = neg 38 39 # Determine the API version, if versioning is in use. 40 version, scheme = self.determine_version(request, *args, **kwargs) 41 request.version, request.versioning_scheme = version, scheme 42 43 # Ensure that the incoming request is permitted 44 self.perform_authentication(request) 45 #***3.执行check_permissions权限方法(有续) 46 self.check_permissions(request) 47 self.check_throttles(request) 48 49 ###########################################################3 50 51 #***3.续 52 def check_permissions(self, request): 53 #***4.执行self.get_permissions方法(有续) 54 for permission in self.get_permissions(): 55 #***6.执行自定义的has_permission方法 56 if not permission.has_permission(request, self): 57 #***7.执行permission_denied(有续) 58 self.permission_denied( 59 request, message=getattr(permission, 'message', None) 60 ) 61 ######################################################### 62 #***4.续 63 def get_permissions(self): 64 #***5.self.permission_classes位自定义的属性(有续) 65 return [permission() for permission in self.permission_classes] 66 ######################################################### 67 #***7.续 68 def permission_denied(self, request, message=None): 69 #False抛错,True不管 70 if request.authenticators and not request.successful_authenticator: 71 raise exceptions.NotAuthenticated() 72 raise exceptions.PermissionDenied(detail=message)
1 class AuthorViewSet(viewsets.ModelViewSet): 2 authentication_classes = [UserAuth,] 3 #***5.续 4 permission_classes = [UserPerms] 5 queryset = Author.objects.all() 6 serializer_class = AuthorModelSerializer
1 class UserPerms(): 2 #***6.续 3 message="您没有查看该数据的权限" #自定义错误信息 4 def has_permission(self,request,view): 5 if request.user.user_type == 3: 6 return True 7 else: 8 return False 9 #符合条件返回True,不符合条件返回False
六.频率组件
1.使用方式
定义频率类
1 class VisitRateThrottle(): 2 def allow_request(request,self,view): 3 if 通过: 4 return True#通过 5 else: 6 return False#不通过,频率超了
指定频率类
1 class AuthorViewSet(viewsets.ModelViewSet): 2 #指定频率类 3 throttle_classes = [VisitRateThrottle,] 4 queryset = Author.objects.all() 5 serializer_class = AuthorModelSerializer
2.限制每分钟 的访问次数
1 from rest_framework.throttling import BaseThrottle 2 VISIT_RECORD={} 3 class VisitRateThrottle(BaseThrottle): 4 5 def __init__(self): 6 self.history=None 7 #定义频率类 8 def allow_request(self,request,view): 9 remote_addr = request.META.get('REMOTE_ADDR') 10 print(remote_addr) 11 import time 12 ctime=time.time() 13 14 if remote_addr not in VISIT_RECORD: 15 VISIT_RECORD[remote_addr]=[ctime,] 16 return True 17 18 history=VISIT_RECORD.get(remote_addr) 19 self.history=history 20 21 while history and history[-1]<ctime-60: 22 history.pop() 23 #每分钟最多访问几次 24 if len(history)<3: 25 history.insert(0,ctime) 26 return True 27 else: 28 return False 29 30 def wait(self): 31 import time 32 ctime=time.time() 33 return 60-(ctime-self.history[-1])
1 class AuthorViewSet(viewsets.ModelViewSet): 2 #指定频率类 3 throttle_classes = [VisitRateThrottle,] 4 queryset = Author.objects.all() 5 serializer_class = AuthorModelSerializer
3.使用DRF的简单频率控制来控制用户访问频率(局部)
定义频率类
1 from rest_framework.throttling import SimpleRateThrottle 2 class RateThrottle(SimpleRateThrottle): 3 rate = "5/m" 4 def get_cache_key(self, request, view): 5 return self.get_ident(request)
1 class AuthorViewSet(viewsets.ModelViewSet): 2 #指定频率类 3 throttle_classes = [RateThrottle,] 4 queryset = Author.objects.all() 5 serializer_class = AuthorModelSerializer
4.使用DRF的简单频率控制来控制用户访问频率(全局)
定义频率类
1 from rest_framework.throttling import SimpleRateThrottle 2 class RateThrottle(SimpleRateThrottle): 3 # 指定访问频率 4 scope = 'visit_rate' 5 # 指定通过什么方式来区分用户 6 def get_cache_key(self, request, view): 7 return self.get_ident(request)
在settings配置文件中
1 REST_FRAMEWORK = { 2 "DEFAULT_THROTTLE_CLASSES": ('app01.throttle.RateThrottle',), 3 "DEFAULT_THROTTLE_RATES": { 4 "visit_rate": "5/m" 5 } 6 }
七.url注册器
使用方式
1 #导入模块 2 from django.urls import path,re_path,include 3 from app01 import views 4 from rest_framework import routers 5 #生成一个注册器的实例对象 6 routers=routers.DefaultRouter() 7 #注册url接口,第一个参数为路径部分,第二个参数为视图类 8 routers.register(r"author",views.AuthorViewSet)
1 #生成url 2 urlpatterns = [ 3 path('admin/', admin.site.urls), 4 # 5 re_path(r"^",include(routers.urls)) 6 ]
前提:只针对viewsets.ModelViewSet的情况
1 class AuthorViewSet(viewsets.ModelViewSet): 2 queryset = Author.objects.all() 3 serializer_class = AuthorModelSerializer
八.响应器
1 #引入模块 2 from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer 3 class AuthorViewSet(viewsets.ModelViewSet): 4 #指定 5 renderer_classes = [JSONRenderer,] 6 queryset = Author.objects.all() 7 serializer_class = AuthorModelSerializer 8 pagination_class = MyPagenation
效果:以前浏览器在访问时,会得到rest_framework为我们提供的页面,
使用JSONRenderer后浏览器只能得到json数据,没有压页面
九.分页器
PageNumberPagination使用方式1
1 #导入模块 2 from rest_framework.pagination import PageNumberPagination 3 class BookView(APIView): 4 def get(self,request): 5 #获取queryset 6 book_list=Book.objects.all() 7 #实例化PageNumberPagination 8 paginater=PageNumberPagination() 9 #调用paginate_queryset方法 10 paged_books=paginater.paginate_queryset(book_list,request,self) 11 #将分页后的数据传入BookModelSerializer 12 bs=BookModelSerializer(paged_books,many=True,context={'request': request}) 13 return Response(bs.data)
注意在settings中配置REST_FRAMEWORK
1 REST_FRAMEWORK = { 2 #原码中会到setting中找PAGE_SIZE,如果找不到会报错 3 "PAGE_SIZE":4, 4 }
方式一中,所有用PageNumberPagination类来分页的数据都会因为全局中的"PAGE_SIZE":4,每页只能分四个
PageNumberPagination使用方式2
自定义一个分页器,继承PageNumberPagination,不同的数据可以每页显示不同的个数
自定义分页器类并继承PageNumberPagination
1 from rest_framework.pagination import PageNumberPagination 2 class MyPagenation(PageNumberPagination): 3 page_size = 3 #每页显示多少条数据 4 page_query_param = 'page' #get查询是?后面的查询条件 5 page_size_query_param = 'size' #?page=2&size=10,第二页临时改成每页显示十条 6 max_page_size = 5 #每页最多显示的数据数
使用自定义的分页器类
1 class BookView(APIView): 2 def get(self,request): 3 #获取queryset 4 book_list=Book.objects.all() 5 #MyPagenation 6 paginater=MyPagenation() 7 #调用paginate_queryset方法 8 paged_books=paginater.paginate_queryset(book_list,request,self) 9 #将分页后的数据传入BookModelSerializer 10 bs=BookModelSerializer(paged_books,many=True,context={'request': request}) 11 return Response(bs.data)
偏移分页 LimitOffsetPagination
1 from rest_framework.pagination import LimitOffsetPagination 2 3 class MyLimitOffsetPagination(LimitOffsetPagination): 4 default_limit = 3 #每页显示几条数据 5 6 class BookView(APIView): 7 def get(self,request): 8 #获取queryset 9 book_list=Book.objects.all() 10 #实例化MyLimitOffsetPagination 11 paginater=MyLimitOffsetPagination() 12 #调用paginate_queryset方法 13 paged_books=paginater.paginate_queryset(book_list,request,self) 14 #将分页后的数据传入BookModelSerializer 15 bs=BookModelSerializer(paged_books,many=True,context={'request': request}) 16 return Response(bs.data)
访问http://127.0.0.1:8000/book/?limit=3&offset=2,表示临时显示三条数据,偏移两条数据
viewsets.ModelViewSet接口数据的分页
1 from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination 2 #自定义分页类 3 class MyPagenation(PageNumberPagination): 4 page_size = 1 5 page_query_param = 'p' 6 page_size_query_param = 'size' 7 max_page_size = 5 8 9 class Aut horViewSet(viewsets.ModelViewSet): 10 queryset = Author.objects.all() 11 serializer_class = AuthorModelSerializer 12 *****为自定义的ModelViewSet类添加pagination_class字段,绑定分页器类 13 pagination_class = MyPagenation