rest_framework

一.解析器組件(parser)

1.編程:數據結構和算法的結合

2.restful規範

定義:url惟必定位資源,http請求方式區分用戶行爲前端

(1)接口設計規範正則表達式

(2)返回數據規範算法

 

(3)錯誤消息規範數據庫

 

3.classbasedview原碼

 

4.restframework下的APIView的請求流程和原碼

下載:pip install djangorestframeworkdjango

引入:from rest_framework import APIView編程

APIView的原碼:json

 

5.POSTMAN工具的使用

可以發各類方式的請求並對請求頭的數據進行修改且對結果進行格式化的工具 api

6.DRF解析器(parser)的請求流程和原碼

解析器:Django只能解析urlencoded格式的數據,經過解析器 能夠解析各類數據類型(json)的數據瀏覽器

(1)使用方式restful

導入模塊

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
本站公眾號
   歡迎關注本站公眾號,獲取更多信息