rest_framework

一.解析器组件(parser)

1.编程:数据结构和算法的结合

2.restful规范

定义:url唯一定位资源,http请求方式区分用户行为

(1)接口设计规范

(2)返回数据规范

 

(3)错误消息规范

 

3.classbasedview原码

 

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) #  返回的是[{},{}]的形式

访问时得到的页面

 

2.post接口设计(添加操作)

 

 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)返回数据

4.put接口设计(更新操作)

 

 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)

5.delete接口设计

 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 }

2.原码剖析

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

 

原文地址:https://www.cnblogs.com/shanghongyun/p/10057776.html