068.Python框架Django之DRF視圖集使用

一 視圖集與路由的使用

使用視圖集ViewSet,可以將一系列邏輯相關的動作放到一個類中:

  • list() 提供一組數據

  • retrieve() 提供單個數據

  • create() 創建數據

  • update() 保存數據

  • destory() 刪除數據

  ViewSet視圖集類不再實現get()、post()等方法,而是實現動作 action 如 list() 、create() 等。

  視圖集只在使用as_view()方法的時候,才會將action動作與具體請求方式對應上。

1.1 常用的視圖集父類

1 ViewSet

  • 繼承自APIView 與 ViewSetMixin作用也與APIView基本類似,提供了身份認證、權限校驗、流量管理等。
  • ViewSet主要通過繼承ViewSetMixin來實現在調用as_view()時傳入字典(如{‘get’:’list’})的映射處理工作。
  • 在ViewSet中,沒有提供任何動作action方法,需要我們自己實現action方法。

2 GenericViewSet

  使用ViewSet通常並不方便,因為list、retrieve、create、update、destory等方法都需要自己編寫,而這些方法與前面講過的Mixin擴展類提供的方法同名,所以我們可以通過繼承Mixin擴展類來複用這些方法而無需自己編寫。但是Mixin擴展類依賴與GenericAPIView,所以還需要繼承GenericAPIView。

  GenericViewSet就幫助我們完成了這樣的繼承工作,繼承自GenericAPIView與ViewSetMixin,在實現了調用as_view()時傳入字典(如{‘get’:’list’})的映射處理工作的同時,還提供了GenericAPIView提供的基礎方法,可以直接搭配Mixin擴展類使用。

3.ModelViewSet

  繼承自GenericViewSet,同時包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。

4.ReadOnlyModelViewSet

  繼承自GenericViewSet,同時包括了ListModelMixin、RetrieveModelMixin。

1.2 視圖集初步使用

創建一個子應用app

(drfdemo) root@darren-virtual-machine:~/PycharmProjects/drfdemo/drf_demo# python3 manage.py startapp collect

註冊

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'students.apps.StudentsConfig',
    'ser.apps.SerConfig',
    'req.apps.ReqConfig',
    'collect.apps.CollectConfig',
]

路由分發

from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('student/',include("students.urls")),
    path('ser/',include("ser.urls")),
    path('req/', include("req.urls")),
    path('collect/', include("collect.urls")),
]

路由配置

(drfdemo) root@darren-virtual-machine:~/PycharmProjects/drfdemo/drf_demo# vim collect/urls.py

from  django.urls import path,re_path
from collect import views

urlpatterns = [
    path('student1/', views.Student1ViewSet.as_view({"get": "get_5"})),
]

序列化文件

(drfdemo) root@darren-virtual-machine:~/PycharmProjects/drfdemo/drf_demo# vim collect/serializers.py 

from students.models import Student
from rest_framework import serializers


class StudentModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = Student
        fields = ["id", "name", "age", "sex"]
        extra_kwargs = {
            "name": {"max_length": 10, "min_length": 4},
            "age": {"max_value": 150, "min_value": 0},
        }

    def validate_name(self, data):
        if data == "root":
            raise serializers.ValidationError("用戶名不能為root!")
        return data

    def validate(self, attrs):
        name = attrs.get('name')
        age = attrs.get('age')

        if name == "alex" and age == 22:
            raise serializers.ValidationError("alex在22時的故事。。。")

        return attrs

視圖文件

from django.shortcuts import render
from rest_framework.viewsets import ViewSet
from students.models import Student
from collect.serializers import StudentModelSerializer

from rest_framework.response import Response
# Create your views here.

class Student1ViewSet(ViewSet):
    def get_5(self,request):
        #取出所有,並切片操作
        queryset = Student.objects.all()[:5]
        #實例化
        serializer = StudentModelSerializer(instance=queryset,many=True)
        return Response(serializer.data)

訪問//127.0.0.1:8000/collect/student1/可以獲取五條數據

 數據庫中數據

mysql> select * from tb_student;

修改id=5的sex為false

數據庫現有數據

獲取5個男性的數據

from django.shortcuts import render
from rest_framework.viewsets import ViewSet
from students.models import Student
from collect.serializers import StudentModelSerializer

from rest_framework.response import Response
# Create your views here.

class Student1ViewSet(ViewSet):
    def get_5(self,request):
        #取出所有,並切片操作
        queryset = Student.objects.all()[:5]
        #實例化
        serializer = StudentModelSerializer(instance=queryset,many=True)
        return Response(serializer.data)
    def get_5_female(self,request):
        queryset = Student.objects.filter(sex=False)[:5]
        serializer = StudentModelSerializer(instance=queryset, many=True)
        return Response(serializer.data)

配置路由

不要在同一個路由的as_view中書寫兩個同樣的鍵的http請求,會產生覆蓋!!!

from  django.urls import path,re_path
from collect import views

urlpatterns = [
    path('student1/', views.Student1ViewSet.as_view({"get": "get_5"})),
    path('student1/get_5_female/', views.Student1ViewSet.as_view({"get": "get_5_female"})),
]

訪問//127.0.0.1:8000/collect/student1/get_5_female/結果如下

 

獲取一條

from  django.urls import path,re_path
from collect import views

urlpatterns = [
    #ViewSet
    path('student1/', views.Student1ViewSet.as_view({"get": "get_5"})),
    path('student1/get_5_female/', views.Student1ViewSet.as_view({"get": "get_5_female"})),
    re_path(r'^student1/(?P<pk>\d+)/$', views.Student1ViewSet.as_view({"get": "get_one"})),
]

配置視圖

from django.shortcuts import render
from rest_framework.viewsets import ViewSet
from students.models import Student
from collect.serializers import StudentModelSerializer

from rest_framework.response import Response
# Create your views here.

class Student1ViewSet(ViewSet):
    def get_5(self,request):
        #取出所有,並切片操作
        queryset = Student.objects.all()[:5]
        #實例化
        serializer = StudentModelSerializer(instance=queryset,many=True)
        return Response(serializer.data)
    def get_5_female(self,request):
        queryset = Student.objects.filter(sex=False)[:5]
        serializer = StudentModelSerializer(instance=queryset, many=True)
        return Response(serializer.data)
    def get_one(self,request,pk):
        student_obj = Student.objects.get(pk=pk)
        serializer = StudentModelSerializer(instance=student_obj)
        return Response(serializer.data)

POSTMAN調試,訪問//127.0.0.1:8000/collect/student1/5/

 

GenericViewSet視圖 

URL路由配置

from  django.urls import path,re_path
from collect import views

urlpatterns = [
    #ViewSet
    path('student1/', views.Student1ViewSet.as_view({"get": "get_5"})),
    path('student1/get_5_female/', views.Student1ViewSet.as_view({"get": "get_5_female"})),
    re_path(r'^student1/(?P<pk>\d+)/$', views.Student1ViewSet.as_view({"get": "get_one"})),
    # GenericViewSet
    path('student2/', views.Student3GenericViewSet.as_view({"get": "get_5"})),
    path('student2/get_5_female/', views.Student3GenericViewSet.as_view({"get": "get_5_female"})),
]

視圖文件

from django.shortcuts import render
from rest_framework.viewsets import ViewSet
from students.models import Student
from collect.serializers import StudentModelSerializer
from rest_framework.response import Response
# Create your views here.

class Student1ViewSet(ViewSet):
    def get_5(self,request):
        #取出所有,並切片操作
        queryset = Student.objects.all()[:5]
        #實例化
        serializer = StudentModelSerializer(instance=queryset,many=True)
        return Response(serializer.data)
    def get_5_female(self,request):
        queryset = Student.objects.filter(sex=False)[:5]
        serializer = StudentModelSerializer(instance=queryset, many=True)
        return Response(serializer.data)
    def get_one(self,request,pk):
        student_obj = Student.objects.get(pk=pk)
        serializer = StudentModelSerializer(instance=student_obj)
        return Response(serializer.data)

from rest_framework.viewsets import GenericViewSet
class Student3GenericViewSet(GenericViewSet):
    serializer_class = StudentModelSerializer
    queryset = Student.objects.all()
    def get_5(self, request):
        student_list = self.get_queryset()[:5]
        serializer = self.get_serializer(instance=student_list, many=True)
        return Response(serializer.data)
    def get_5_female(self, request):
        student_list = self.get_queryset().filter(sex=False)[:5]
        serializer = self.get_serializer(instance=student_list, many=True)
        return Response(serializer.data)

POSTMAN調試

1.3 GenericViewSet結合模型類

可以和模型類進行組合快速生成基本的API接口

url路由配置

from  django.urls import path,re_path
from collect import views

urlpatterns = [
    #ViewSet
    path('student1/', views.Student1ViewSet.as_view({"get": "get_5"})),
    path('student1/get_5_female/', views.Student1ViewSet.as_view({"get": "get_5_female"})),
    re_path(r'^student1/(?P<pk>\d+)/$', views.Student1ViewSet.as_view({"get": "get_one"})),
    # GenericViewSet
    path('student2/', views.Student3GenericViewSet.as_view({"get": "get_5"})),
    path('student2/get_5_female/', views.Student3GenericViewSet.as_view({"get": "get_5_female"})),
    # GenericViewSet和模型類進行組合快速生成基本的API接口,當使用get,觸發list的方法,當使用POST請求,觸發create方法
    path("students3/", views.Student4GenericViewSet.as_view({"get": "list", "post": "create"})),
]

視圖文件

from django.shortcuts import render
from rest_framework.viewsets import ViewSet
from students.models import Student
from collect.serializers import StudentModelSerializer

from rest_framework.response import Response
# Create your views here.

class Student1ViewSet(ViewSet):
    def get_5(self,request):
        #取出所有,並切片操作
        queryset = Student.objects.all()[:5]
        #實例化
        serializer = StudentModelSerializer(instance=queryset,many=True)
        return Response(serializer.data)
    def get_5_female(self,request):
        queryset = Student.objects.filter(sex=False)[:5]
        serializer = StudentModelSerializer(instance=queryset, many=True)
        return Response(serializer.data)
    def get_one(self,request,pk):
        student_obj = Student.objects.get(pk=pk)
        serializer = StudentModelSerializer(instance=student_obj)
        return Response(serializer.data)

from rest_framework.viewsets import GenericViewSet
class Student3GenericViewSet(GenericViewSet):
    serializer_class = StudentModelSerializer
    queryset = Student.objects.all()
    def get_5(self, request):
        student_list = self.get_queryset()[:5]
        serializer = self.get_serializer(instance=student_list, many=True)
        return Response(serializer.data)
    def get_5_female(self, request):
        student_list = self.get_queryset().filter(sex=False)[:5]
        serializer = self.get_serializer(instance=student_list, many=True)
        return Response(serializer.data)
    
from rest_framework.mixins import ListModelMixin, CreateModelMixin
class Student4GenericViewSet(GenericViewSet, ListModelMixin, CreateModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

POSTMAN調試

get請求

 POST請求

 

 查看數據庫

 

1.4 ModelViewSet配置

url配置

from  django.urls import path,re_path
from collect import views

urlpatterns = [
    #ViewSet
    path('student1/', views.Student1ViewSet.as_view({"get": "get_5"})),
    path('student1/get_5_female/', views.Student1ViewSet.as_view({"get": "get_5_female"})),
    re_path(r'^student1/(?P<pk>\d+)/$', views.Student1ViewSet.as_view({"get": "get_one"})),
    # GenericViewSet
    path('student2/', views.Student3GenericViewSet.as_view({"get": "get_5"})),
    path('student2/get_5_female/', views.Student3GenericViewSet.as_view({"get": "get_5_female"})),
    # GenericViewSet和模型類進行組合快速生成基本的API接口
    path("student3/", views.Student4GenericViewSet.as_view({"get": "list", "post": "create"})),
    # ModelViewSet 默認提供了5個API接口
    path("student4/", views.Student5ModelViewSet.as_view({"post": "create", "get": "list"})),
    re_path(r"^student4/(?P<pk>\d+)/$",
            views.Student5ModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
]

views

from django.shortcuts import render
from rest_framework.viewsets import ViewSet
from students.models import Student
from collect.serializers import StudentModelSerializer

from rest_framework.response import Response
# Create your views here.

class Student1ViewSet(ViewSet):
    def get_5(self,request):
        #取出所有,並切片操作
        queryset = Student.objects.all()[:5]
        #實例化
        serializer = StudentModelSerializer(instance=queryset,many=True)
        return Response(serializer.data)
    def get_5_female(self,request):
        queryset = Student.objects.filter(sex=False)[:5]
        serializer = StudentModelSerializer(instance=queryset, many=True)
        return Response(serializer.data)
    def get_one(self,request,pk):
        student_obj = Student.objects.get(pk=pk)
        serializer = StudentModelSerializer(instance=student_obj)
        return Response(serializer.data)

from rest_framework.viewsets import GenericViewSet
class Student3GenericViewSet(GenericViewSet):
    serializer_class = StudentModelSerializer
    queryset = Student.objects.all()
    def get_5(self, request):
        student_list = self.get_queryset()[:5]
        serializer = self.get_serializer(instance=student_list, many=True)
        return Response(serializer.data)
    def get_5_female(self, request):
        student_list = self.get_queryset().filter(sex=False)[:5]
        serializer = self.get_serializer(instance=student_list, many=True)
        return Response(serializer.data)

from rest_framework.mixins import ListModelMixin, CreateModelMixin
class Student4GenericViewSet(GenericViewSet, ListModelMixin, CreateModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

from rest_framework.viewsets import ModelViewSet
class Student5ModelViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

POSTMAN調試

獲取所有

 POST添加

數據庫

PUT修改

數據庫

delete刪除

 

數據庫

mysql> select * from tb_student;
+----+------------+-----+-----+------------+-------------------+
| id | name       | sex | age | class_null | description       |
+----+------------+-----+-----+------------+-------------------+
|  1 | 令狐沖     |   1 |  18 | 205        | hello mysqlf      |
|  2 | 任我行     |   1 |  55 | 203        | hello let me go   |
|  3 | 李尋歡     |   1 |  33 | 207        | be happy lee      |
|  5 | limochu    |   0 |  36 | 208        | Don』t Worry Lee   |
|  6 | mchaofeng  |   1 |  26 |            |                   |
|  7 | yangguo    |   1 |  25 |            |                   |
|  8 | xiaolongnv |   0 |  25 |            |                   |
+----+------------+-----+-----+------------+-------------------+

1.5 ReadOnlyModelViewSet配置

url路由配置

from  django.urls import path,re_path
from collect import views

urlpatterns = [
    #ViewSet
    path('student1/', views.Student1ViewSet.as_view({"get": "get_5"})),
    path('student1/get_5_female/', views.Student1ViewSet.as_view({"get": "get_5_female"})),
    re_path(r'^student1/(?P<pk>\d+)/$', views.Student1ViewSet.as_view({"get": "get_one"})),
    # GenericViewSet
    path('student2/', views.Student3GenericViewSet.as_view({"get": "get_5"})),
    path('student2/get_5_female/', views.Student3GenericViewSet.as_view({"get": "get_5_female"})),
    # GenericViewSet和模型類進行組合快速生成基本的API接口
    path("student3/", views.Student4GenericViewSet.as_view({"get": "list", "post": "create"})),
    # ModelViewSet 默認提供了5個API接口
    path("student4/", views.Student5ModelViewSet.as_view({"post": "create", "get": "list"})),
    re_path(r"^student4/(?P<pk>\d+)/$",
            views.Student5ModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
    # ReadOnlyModelViewSet
    path("student5/", views.Student6ReadOnlyModelViewSet.as_view({"get": "list"})),
    re_path(r"^student5/(?P<pk>\d+)/$", views.Student6ReadOnlyModelViewSet.as_view({"get": "retrieve"})),
]

view視圖配置

from django.shortcuts import render
from rest_framework.viewsets import ViewSet
from students.models import Student
from collect.serializers import StudentModelSerializer

from rest_framework.response import Response
# Create your views here.

class Student1ViewSet(ViewSet):
    def get_5(self,request):
        #取出所有,並切片操作
        queryset = Student.objects.all()[:5]
        #實例化
        serializer = StudentModelSerializer(instance=queryset,many=True)
        return Response(serializer.data)
    def get_5_female(self,request):
        queryset = Student.objects.filter(sex=False)[:5]
        serializer = StudentModelSerializer(instance=queryset, many=True)
        return Response(serializer.data)
    def get_one(self,request,pk):
        student_obj = Student.objects.get(pk=pk)
        serializer = StudentModelSerializer(instance=student_obj)
        return Response(serializer.data)

from rest_framework.viewsets import GenericViewSet
class Student3GenericViewSet(GenericViewSet):
    serializer_class = StudentModelSerializer
    queryset = Student.objects.all()
    def get_5(self, request):
        student_list = self.get_queryset()[:5]
        serializer = self.get_serializer(instance=student_list, many=True)
        return Response(serializer.data)
    def get_5_female(self, request):
        student_list = self.get_queryset().filter(sex=False)[:5]
        serializer = self.get_serializer(instance=student_list, many=True)
        return Response(serializer.data)

from rest_framework.mixins import ListModelMixin, CreateModelMixin
class Student4GenericViewSet(GenericViewSet, ListModelMixin, CreateModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

from rest_framework.viewsets import ModelViewSet
class Student5ModelViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

from rest_framework.viewsets import ReadOnlyModelViewSet
class Student6ReadOnlyModelViewSet(ReadOnlyModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

只有get方法

 

獲取一條

二 路由類的使用

有了視圖集以後,視圖文件中多個視圖類可以合併成一個,但是,路由的代碼就變得複雜了, 需要我們經常在as_view方法 ,編寫http請求和視圖方法的對應關係, 事實上,在路由中,DRF也提供了一個路由類給我們對路由的代碼進行簡寫。 當然,這個路由類僅針對於 視圖集 才可以使用。

2.1 路由類基本配置

url路由配置

from  django.urls import path,re_path
from collect import views

urlpatterns = [
    #ViewSet
    path('student1/', views.Student1ViewSet.as_view({"get": "get_5"})),
    path('student1/get_5_female/', views.Student1ViewSet.as_view({"get": "get_5_female"})),
    re_path(r'^student1/(?P<pk>\d+)/$', views.Student1ViewSet.as_view({"get": "get_one"})),
    # GenericViewSet
    path('student2/', views.Student3GenericViewSet.as_view({"get": "get_5"})),
    path('student2/get_5_female/', views.Student3GenericViewSet.as_view({"get": "get_5_female"})),
    # GenericViewSet和模型類進行組合快速生成基本的API接口
    path("student3/", views.Student4GenericViewSet.as_view({"get": "list", "post": "create"})),
    # ModelViewSet 默認提供了5個API接口
    path("student4/", views.Student5ModelViewSet.as_view({"post": "create", "get": "list"})),
    re_path(r"^student4/(?P<pk>\d+)/$",
            views.Student5ModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
    # ReadOnlyModelViewSet
    path("student5/", views.Student6ReadOnlyModelViewSet.as_view({"get": "list"})),
    re_path(r"^student5/(?P<pk>\d+)/$", views.Student6ReadOnlyModelViewSet.as_view({"get": "retrieve"})),
]

# 路由類默認只會給視圖集中的基本5個API生成地址[ 獲取一條,獲取多條,添加.刪除,修改數據 ]
from rest_framework.routers import DefaultRouter
# 實例化路由類
router = DefaultRouter()
# router.register("訪問地址前綴","視圖集類","訪問別名")
# 註冊視圖視圖集類
router.register("student7", views.Student7ModelViewSet)

print(router.urls)
# 把路由列表註冊到django項目中
urlpatterns += router.urls

views視圖文件

from django.shortcuts import render
from rest_framework.viewsets import ViewSet
from students.models import Student
from collect.serializers import StudentModelSerializer

from rest_framework.response import Response
# Create your views here.

class Student1ViewSet(ViewSet):
    def get_5(self,request):
        #取出所有,並切片操作
        queryset = Student.objects.all()[:5]
        #實例化
        serializer = StudentModelSerializer(instance=queryset,many=True)
        return Response(serializer.data)
    def get_5_female(self,request):
        queryset = Student.objects.filter(sex=False)[:5]
        serializer = StudentModelSerializer(instance=queryset, many=True)
        return Response(serializer.data)
    def get_one(self,request,pk):
        student_obj = Student.objects.get(pk=pk)
        serializer = StudentModelSerializer(instance=student_obj)
        return Response(serializer.data)

from rest_framework.viewsets import GenericViewSet
class Student3GenericViewSet(GenericViewSet):
    serializer_class = StudentModelSerializer
    queryset = Student.objects.all()
    def get_5(self, request):
        student_list = self.get_queryset()[:5]
        serializer = self.get_serializer(instance=student_list, many=True)
        return Response(serializer.data)
    def get_5_female(self, request):
        student_list = self.get_queryset().filter(sex=False)[:5]
        serializer = self.get_serializer(instance=student_list, many=True)
        return Response(serializer.data)

from rest_framework.mixins import ListModelMixin, CreateModelMixin
class Student4GenericViewSet(GenericViewSet, ListModelMixin, CreateModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

from rest_framework.viewsets import ModelViewSet
class Student5ModelViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

from rest_framework.viewsets import ReadOnlyModelViewSet
class Student6ReadOnlyModelViewSet(ReadOnlyModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

from rest_framework.decorators import action
class Student7ModelViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

重啟之後,查看print打印內容

[
<URLPattern '^student7/$' [name='student-list']>,
<URLPattern '^student7\.(?P<format>[a-z0-9]+)/?$' [name='student-list']>,
<URLPattern '^student7/(?P<pk>[^/.]+)/$' [name='student-detail']>,
<URLPattern '^student7/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$' [name='student-detail']>,
<URLPattern '^$' [name='api-root']>,
<URLPattern '^\.(?P<format>[a-z0-9]+)/?$' [name='api-root']>
]

POSTMAN調試

獲取所有

2.2 自定義方法並調用

添加進views方法中 

from django.shortcuts import render
from rest_framework.viewsets import ViewSet
from students.models import Student
from collect.serializers import StudentModelSerializer

from rest_framework.response import Response
# Create your views here.

class Student1ViewSet(ViewSet):
    def get_5(self,request):
        #取出所有,並切片操作
        queryset = Student.objects.all()[:5]
        #實例化
        serializer = StudentModelSerializer(instance=queryset,many=True)
        return Response(serializer.data)
    def get_5_female(self,request):
        queryset = Student.objects.filter(sex=False)[:5]
        serializer = StudentModelSerializer(instance=queryset, many=True)
        return Response(serializer.data)
    def get_one(self,request,pk):
        student_obj = Student.objects.get(pk=pk)
        serializer = StudentModelSerializer(instance=student_obj)
        return Response(serializer.data)

from rest_framework.viewsets import GenericViewSet
class Student3GenericViewSet(GenericViewSet):
    serializer_class = StudentModelSerializer
    queryset = Student.objects.all()
    def get_5(self, request):
        student_list = self.get_queryset()[:5]
        serializer = self.get_serializer(instance=student_list, many=True)
        return Response(serializer.data)
    def get_5_female(self, request):
        student_list = self.get_queryset().filter(sex=False)[:5]
        serializer = self.get_serializer(instance=student_list, many=True)
        return Response(serializer.data)

from rest_framework.mixins import ListModelMixin, CreateModelMixin
class Student4GenericViewSet(GenericViewSet, ListModelMixin, CreateModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

from rest_framework.viewsets import ModelViewSet
class Student5ModelViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

from rest_framework.viewsets import ReadOnlyModelViewSet
class Student6ReadOnlyModelViewSet(ReadOnlyModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

from rest_framework.decorators import action
class Student7ModelViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    # methods 指定允許哪些http請求訪問當前視圖方法
    # detail  指定生成的路由地址中是否要夾帶pk值,True為需要
    # @action(methods=['get'], detail=False)
    # def get_4(self, request):
    @action(methods=['get'], detail=True)
    def get_5(self, request, pk):
        serilizer = self.get_serializer(instance=self.get_queryset().get(pk=pk))
        return Response(serilizer.data)

重啟查看打印信息

[
<URLPattern '^student7/$' [name='student-list']>,
<URLPattern '^student7\.(?P<format>[a-z0-9]+)/?$' [name='student-list']>,
<URLPattern '^student7/(?P<pk>[^/.]+)/$' [name='student-detail']>,
<URLPattern '^student7/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$' [name='student-detail']>,
<URLPattern '^student7/(?P<pk>[^/.]+)/get_5/$' [name='student-get-5']>,
<URLPattern '^student7/(?P<pk>[^/.]+)/get_5\.(?P<format>[a-z0-9]+)/?$' [name='student-get-5']>,
<URLPattern '^$' [name='api-root']>,
<URLPattern '^\.(?P<format>[a-z0-9]+)/?$' [name='api-root']>]

POSTMAN訪問自定義方法

 

2.3 在一個視圖類調用多個視圖劃器類 

url路由配置

from  django.urls import path,re_path
from collect import views

urlpatterns = [
    #ViewSet
    path('student1/', views.Student1ViewSet.as_view({"get": "get_5"})),
    path('student1/get_5_female/', views.Student1ViewSet.as_view({"get": "get_5_female"})),
    re_path(r'^student1/(?P<pk>\d+)/$', views.Student1ViewSet.as_view({"get": "get_one"})),
    # GenericViewSet
    path('student2/', views.Student3GenericViewSet.as_view({"get": "get_5"})),
    path('student2/get_5_female/', views.Student3GenericViewSet.as_view({"get": "get_5_female"})),
    # GenericViewSet和模型類進行組合快速生成基本的API接口
    path("student3/", views.Student4GenericViewSet.as_view({"get": "list", "post": "create"})),
    # ModelViewSet 默認提供了5個API接口
    path("student4/", views.Student5ModelViewSet.as_view({"post": "create", "get": "list"})),
    re_path(r"^student4/(?P<pk>\d+)/$",
            views.Student5ModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
    # ReadOnlyModelViewSet
    path("student5/", views.Student6ReadOnlyModelViewSet.as_view({"get": "list"})),
    re_path(r"^student5/(?P<pk>\d+)/$", views.Student6ReadOnlyModelViewSet.as_view({"get": "retrieve"})),
    # 一個視圖類中調用多個序列化器
    path("student8/", views.Student8GenericAPIView.as_view()),
]

# 路由類默認只會給視圖集中的基本5個API生成地址[ 獲取一條,獲取多條,添加.刪除,修改數據 ]
from rest_framework.routers import DefaultRouter
# 實例化路由類
router = DefaultRouter()
# router.register("訪問地址前綴","視圖集類","訪問別名")
# 註冊視圖視圖集類
router.register("student7", views.Student7ModelViewSet)

print(router.urls)
# 把路由列表註冊到django項目中
urlpatterns += router.urls

view視圖配置

from django.shortcuts import render
from rest_framework.viewsets import ViewSet
from students.models import Student
from collect.serializers import StudentModelSerializer

from rest_framework.response import Response
# Create your views here.

class Student1ViewSet(ViewSet):
    def get_5(self,request):
        #取出所有,並切片操作
        queryset = Student.objects.all()[:5]
        #實例化
        serializer = StudentModelSerializer(instance=queryset,many=True)
        return Response(serializer.data)
    def get_5_female(self,request):
        queryset = Student.objects.filter(sex=False)[:5]
        serializer = StudentModelSerializer(instance=queryset, many=True)
        return Response(serializer.data)
    def get_one(self,request,pk):
        student_obj = Student.objects.get(pk=pk)
        serializer = StudentModelSerializer(instance=student_obj)
        return Response(serializer.data)

from rest_framework.viewsets import GenericViewSet
class Student3GenericViewSet(GenericViewSet):
    serializer_class = StudentModelSerializer
    queryset = Student.objects.all()
    def get_5(self, request):
        student_list = self.get_queryset()[:5]
        serializer = self.get_serializer(instance=student_list, many=True)
        return Response(serializer.data)
    def get_5_female(self, request):
        student_list = self.get_queryset().filter(sex=False)[:5]
        serializer = self.get_serializer(instance=student_list, many=True)
        return Response(serializer.data)

from rest_framework.mixins import ListModelMixin, CreateModelMixin
class Student4GenericViewSet(GenericViewSet, ListModelMixin, CreateModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

from rest_framework.viewsets import ModelViewSet
class Student5ModelViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

from rest_framework.viewsets import ReadOnlyModelViewSet
class Student6ReadOnlyModelViewSet(ReadOnlyModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

from rest_framework.decorators import action
class Student7ModelViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    # methods 指定允許哪些http請求訪問當前視圖方法
    # detail  指定生成的路由地址中是否要夾帶pk值,True為需要
    # @action(methods=['get'], detail=False)
    # def get_4(self, request):
    @action(methods=['get'], detail=True)
    def get_5(self, request, pk):
        serilizer = self.get_serializer(instance=self.get_queryset().get(pk=pk))
        return Response(serilizer.data)

from rest_framework.generics import GenericAPIView
from collect.serializers import StudentInfoModelSerializer
class Student8GenericAPIView(GenericAPIView):
    queryset = Student.objects.all()

    # GenericAPI內部調用序列化器的方法,我們可以重寫這個方法來實現根據不同的需求來調用不同的序列化器
    def get_serializer_class(self):
        if self.request.method == "GET":
            # 2個字段
            return StudentInfoModelSerializer
        return StudentModelSerializer

    def get(self, request):
        """獲取所有數據的id和name"""
        student_list = self.get_queryset()
        serializer = self.get_serializer(instance=student_list, many=True)
        # serializer = StudentInfoModelSerializer(instance=student_list, many=True)
        return Response(serializer.data)

    def post(self, request):
        """添加數據"""
        data = request.data
        serializer = self.get_serializer(data=data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data)

序列化類

(drfdemo) root@darren-virtual-machine:~/PycharmProjects/drfdemo/drf_demo# vim collect/serializers.py

from students.models import Student
from rest_framework import serializers

class StudentModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Student
        fields = ["id", "name", "age", "sex"]
        extra_kwargs = {
            "name": {"max_length": 10, "min_length": 4},
            "age": {"max_value": 150, "min_value": 0},
        }
    def validate_name(self, data):
        if data == "root":
            raise serializers.ValidationError("用戶名不能為root!")
        return data
    def validate(self, attrs):
        name = attrs.get('name')
        age = attrs.get('age')

        if name == "alex" and age == 22:
            raise serializers.ValidationError("alex在22時的故事。。。")
        return attrs

class StudentInfoModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Student
        fields = ["id", "name"]

訪問//127.0.0.1:8000/collect/student8/

只有兩個字段

2.4 視圖集內使用多個序列化類

url配置

from  django.urls import path,re_path
from collect import views

urlpatterns = [
    #ViewSet
    path('student1/', views.Student1ViewSet.as_view({"get": "get_5"})),
    path('student1/get_5_female/', views.Student1ViewSet.as_view({"get": "get_5_female"})),
    re_path(r'^student1/(?P<pk>\d+)/$', views.Student1ViewSet.as_view({"get": "get_one"})),
    # GenericViewSet
    path('student2/', views.Student3GenericViewSet.as_view({"get": "get_5"})),
    path('student2/get_5_female/', views.Student3GenericViewSet.as_view({"get": "get_5_female"})),
    # GenericViewSet和模型類進行組合快速生成基本的API接口
    path("student3/", views.Student4GenericViewSet.as_view({"get": "list", "post": "create"})),
    # ModelViewSet 默認提供了5個API接口
    path("student4/", views.Student5ModelViewSet.as_view({"post": "create", "get": "list"})),
    re_path(r"^student4/(?P<pk>\d+)/$",
            views.Student5ModelViewSet.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
    # ReadOnlyModelViewSet
    path("student5/", views.Student6ReadOnlyModelViewSet.as_view({"get": "list"})),
    re_path(r"^student5/(?P<pk>\d+)/$", views.Student6ReadOnlyModelViewSet.as_view({"get": "retrieve"})),
    # 一個視圖類中調用多個序列化器
    path("student8/", views.Student8GenericAPIView.as_view()),
    # 一個視圖集中調用多個序列化器
    path("student9/", views.Student9ModelViewSet.as_view({"get": "list"})),
    re_path(r"^student9/(?P<pk>\d+)/$", views.Student9ModelViewSet.as_view({"get": "retrieve"})),
]

# 路由類默認只會給視圖集中的基本5個API生成地址[ 獲取一條,獲取多條,添加.刪除,修改數據 ]
from rest_framework.routers import DefaultRouter
# 實例化路由類
router = DefaultRouter()
# router.register("訪問地址前綴","視圖集類","訪問別名")
# 註冊視圖視圖集類
router.register("student7", views.Student7ModelViewSet)

print(router.urls)
# 把路由列表註冊到django項目中
urlpatterns += router.urls

views配置

要求:

  • 列表數據list,返回2個字段,
  • 詳情數據retrieve,返回所有字段 
from django.shortcuts import render
from rest_framework.viewsets import ViewSet
from students.models import Student
from collect.serializers import StudentModelSerializer

from rest_framework.response import Response
# Create your views here.

class Student1ViewSet(ViewSet):
    def get_5(self,request):
        #取出所有,並切片操作
        queryset = Student.objects.all()[:5]
        #實例化
        serializer = StudentModelSerializer(instance=queryset,many=True)
        return Response(serializer.data)
    def get_5_female(self,request):
        queryset = Student.objects.filter(sex=False)[:5]
        serializer = StudentModelSerializer(instance=queryset, many=True)
        return Response(serializer.data)
    def get_one(self,request,pk):
        student_obj = Student.objects.get(pk=pk)
        serializer = StudentModelSerializer(instance=student_obj)
        return Response(serializer.data)

from rest_framework.viewsets import GenericViewSet
class Student3GenericViewSet(GenericViewSet):
    serializer_class = StudentModelSerializer
    queryset = Student.objects.all()
    def get_5(self, request):
        student_list = self.get_queryset()[:5]
        serializer = self.get_serializer(instance=student_list, many=True)
        return Response(serializer.data)
    def get_5_female(self, request):
        student_list = self.get_queryset().filter(sex=False)[:5]
        serializer = self.get_serializer(instance=student_list, many=True)
        return Response(serializer.data)

from rest_framework.mixins import ListModelMixin, CreateModelMixin
class Student4GenericViewSet(GenericViewSet, ListModelMixin, CreateModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

from rest_framework.viewsets import ModelViewSet
class Student5ModelViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

from rest_framework.viewsets import ReadOnlyModelViewSet
class Student6ReadOnlyModelViewSet(ReadOnlyModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

from rest_framework.decorators import action
class Student7ModelViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    # methods 指定允許哪些http請求訪問當前視圖方法
    # detail  指定生成的路由地址中是否要夾帶pk值,True為需要
    # @action(methods=['get'], detail=False)
    # def get_4(self, request):
    @action(methods=['get'], detail=True)
    def get_5(self, request, pk):
        serilizer = self.get_serializer(instance=self.get_queryset().get(pk=pk))
        return Response(serilizer.data)

from rest_framework.generics import GenericAPIView
from collect.serializers import StudentInfoModelSerializer
class Student8GenericAPIView(GenericAPIView):
    queryset = Student.objects.all()

    # GenericAPI內部調用序列化器的方法,我們可以重寫這個方法來實現根據不同的需求來調用不同的序列化器
    def get_serializer_class(self):
        if self.request.method == "GET":
            # 2個字段
            return StudentInfoModelSerializer
        return StudentModelSerializer

    def get(self, request):
        """獲取所有數據的id和name"""
        student_list = self.get_queryset()

        serializer = self.get_serializer(instance=student_list, many=True)
        # serializer = StudentInfoModelSerializer(instance=student_list, many=True)

        return Response(serializer.data)

    def post(self, request):
        """添加數據"""
        data = request.data
        serializer = self.get_serializer(data=data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data)

class Student9ModelViewSet(ModelViewSet):
    queryset = Student.objects.all()
    def get_serializer_class(self):
        # 本次客戶端請求的視圖方法名  self.action
        print(self.action)
        if self.action == "list":
            return StudentInfoModelSerializer
        return StudentModelSerializer

get獲取所有,只返回兩個字段

打印的結果是list

輸出單個信息,會輸出4個字段

方法名稱

三  DRF的擴展功能

創建新的app應用

(drfdemo) root@darren-virtual-machine:~/PycharmProjects/drfdemo/drf_demo# python3 manage.py startapp opt

註冊

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'students.apps.StudentsConfig',
    'ser.apps.SerConfig',
    'req.apps.ReqConfig',
    'collect.apps.CollectConfig',
    'opt.apps.OptConfig',
]

配置字體

LANGUAGE_CODE = 'zh-hans'

添加路由分發

from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('student/',include("students.urls")),
    path('ser/',include("ser.urls")),
    path('req/', include("req.urls")),
    path('collect/', include("collect.urls")),
    path('opt/', include("opt.urls")),
]

3.1 用戶控制

創建路由文件

(drfdemo) root@darren-virtual-machine:~/PycharmProjects/drfdemo/drf_demo# vim opt/urls.py

from django.urls import path
from opt import views

urlpatterns = [
    path('auth1/', views.Demo1APIView.as_view()),
    path('auth2/', views.Demo2APIView.as_view()),
]

views文件

from django.shortcuts import render
# Create your views here.
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, IsAdminUser

#用戶的認證和權限識別
class Demo1APIView(APIView):
    #只允許登錄後的用戶訪問
    permission_classes = [IsAuthenticated]
    def get(self, request):
        #個人中心
        return Response("個人中心")

class Demo2APIView(APIView):
    #只允許管理員訪問
    permission_classes = [IsAdminUser]
    def get(self, request):
        #個人中心2
        return Response("個人中心2")

訪問//127.0.0.1:8000/opt/auth1/

創建一個admin用戶進行管理

 

登錄//127.0.0.1:8000/admin/login/?next=/admin/ 

登陸後,查看//127.0.0.1:8000/opt/auth1/和 //127.0.0.1:8000/opt/auth2/

創建一個alex用戶

使用alex登錄,同時取消人員狀態

然後auth1可以正常訪問,但是訪問//127.0.0.1:8000/opt/auth2/

必須是一個超級管理員用戶才能看見

查看數據的seeeion

 mysql> select * from django_session;

+----------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------+
| session_key                      | session_data                                                                                                                                                                                                                                                 | expire_date                |
+----------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------+
| fn55zqveedvfjckalewwusqny7iadhun | MWM5NDBiNmI0ZDZlYTFmZmM4MjE4YTkyODcyMWNmNTQ4NjJkNDJkNTp7Il9hdXRoX3VzZXJfaWQiOiIyIiwiX2F1dGhfdXNlcl9iYWNrZW5kIjoiZGphbmdvLmNvbnRyaWIuYXV0aC5iYWNrZW5kcy5Nb2RlbEJhY2tlbmQiLCJfYXV0aF91c2VyX2hhc2giOiIwMTY2ZDUxMTFhYzU2ZTBjMWRkZDU5ZmM3MmE5ZmI1ZjcyYWY4NmMxIn0= | 2020-05-05 07:27:10.353593 |
+----------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------+

3.2 權限Permissions控制

權限控制可以限制用戶對於視圖的訪問和對於具體數據對象的訪問。

  • 在執行視圖的dispatch()方法前,會先進行視圖訪問權限的判斷

  • 在通過get_object()獲取具體對象時,會進行模型對象訪問權限的判斷

內置提供的權限:

  • AllowAny 允許所有用戶

  • IsAuthenticated 僅通過認證的用戶

  • IsAdminUser 僅管理員用戶

  • IsAuthenticatedOrReadOnly 已經登陸認證的用戶可以對數據進行增刪改操作,沒有登陸認證的只能查看數據。

可以在配置文件中全局設置默認的權限管理類,如:

REST_FRAMEWORK = {
    ....
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    )
}

如果未指明,則採用如下默認配置

'DEFAULT_PERMISSION_CLASSES': (
   'rest_framework.permissions.AllowAny',

 自定義權限

url配置

from django.urls import path,re_path
from opt import views

urlpatterns = [
    path('auth1/', views.Demo1APIView.as_view()),
    path('auth2/', views.Demo2APIView.as_view()),
    # 自定義權限
    path('auth3/', views.Demo3APIView.as_view()),
]

views配置

from django.shortcuts import render
# Create your views here.
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, IsAdminUser

#用戶的認證和權限識別
class Demo1APIView(APIView):
    #只允許登錄後的用戶訪問
    permission_classes = [IsAuthenticated]
    def get(self, request):
        #個人中心
        return Response("個人中心")

class Demo2APIView(APIView):
    #只允許管理員訪問
    permission_classes = [IsAdminUser]
    def get(self, request):
        #個人中心2
        return Response("個人中心2")

# 自定義權限
from rest_framework.permissions import BasePermission

class MyPermission(BasePermission):
    def has_permission(self, request, view):
        """
        針對訪問視圖進行權限判斷
        :param request: 本次操作的http請求對象
        :param view:  本次訪問路由對應的視圖對象
        :return:
        """
        if request.user.username == "xiaoming":
            return True
        return False

class Demo3APIView(APIView):
    permission_classes = [MyPermission]

    def get(self, request):
        """個人中心3"""
        return Response("個人中心3")

創建xiaoming用戶

(drfdemo) root@darren-virtual-machine:~/PycharmProjects/drfdemo/drf_demo# python3 manage.py createsuperuser

使用root登錄訪問auth3

使用ixaoming用戶登錄訪問

3.3  限流Throttling

可以對接口訪問的頻次進行限制,以減輕服務器壓力。

一般用於付費購買次數,投票等場景使用.

可以在配置文件中,使用DEFAULT_THROTTLE_CLASSES 和 DEFAULT_THROTTLE_RATES進行全局配置

(drfdemo) root@darren-virtual-machine:~/PycharmProjects/drfdemo/drf_demo# vim drf_demo/settings.py 

REST_FRAMEWORK = {
    # 限流
    'DEFAULT_THROTTLE_CLASSES': (  # 對全局進行設置
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ),
    'DEFAULT_THROTTLE_RATES': {
        'anon': '3/hour',
        'user': '3/minute',
    }
}

DEFAULT_THROTTLE_RATES 可以使用 second, minute, hour 或day來指明周期。

URL文件

from django.urls import path,re_path
from opt import views

urlpatterns = [
    path('auth1/', views.Demo1APIView.as_view()),
    path('auth2/', views.Demo2APIView.as_view()),
    # 自定義權限
    path('auth3/', views.Demo3APIView.as_view()),
    # 限流
    path('auth4/', views.Demo4APIView.as_view()),
]

views視圖文件

from django.shortcuts import render
# Create your views here.
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, IsAdminUser

#用戶的認證和權限識別
class Demo1APIView(APIView):
    #只允許登錄後的用戶訪問
    permission_classes = [IsAuthenticated]
    def get(self, request):
        #個人中心
        return Response("個人中心")

class Demo2APIView(APIView):
    #只允許管理員訪問
    permission_classes = [IsAdminUser]
    def get(self, request):
        #個人中心2
        return Response("個人中心2")

# 自定義權限
from rest_framework.permissions import BasePermission

class MyPermission(BasePermission):
    def has_permission(self, request, view):
        """
        針對訪問視圖進行權限判斷,必須使用xiaoming用戶
        :param request: 本次操作的http請求對象
        :param view:  本次訪問路由對應的視圖對象
        :return:
        """
        if request.user.username == "xiaoming":
            return True
        return False

class Demo3APIView(APIView):
    permission_classes = [MyPermission]

    def get(self, request):
        """個人中心3"""
        return Response("個人中心3")

# 限流
from rest_framework.throttling import UserRateThrottle, AnonRateThrottle
class Demo4APIView(APIView):
    throttle_classes = [UserRateThrottle, AnonRateThrottle]  # 全局配置後,這裡就不用指定
    def get(self, request):
        """投票頁面"""
        return Response("投票頁面")

訪問auth4

當超過3次

 

 註銷用戶,使用匿名用戶次數超標

 

3.4  過濾Filtering

對於列表數據可能需要根據字段進行過濾,我們可以通過添加django-fitlter擴展來增強支持。

安裝django-filter

(drfdemo) root@darren-virtual-machine:~/PycharmProjects/drfdemo/drf_demo# pip3 install django-filter

註冊

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    
    'rest_framework',
    'django_filters',  # 需要註冊應用,
    
    'students.apps.StudentsConfig',
    'ser.apps.SerConfig',
    'req.apps.ReqConfig',
    'collect.apps.CollectConfig',
    'opt.apps.OptConfig',
]

配置url路由

from django.urls import path,re_path
from opt import views

urlpatterns = [
    path('auth1/', views.Demo1APIView.as_view()),
    path('auth2/', views.Demo2APIView.as_view()),
    # 自定義權限
    path('auth3/', views.Demo3APIView.as_view()),
    # 限流
    path('auth4/', views.Demo4APIView.as_view()),
    # 過濾
    path('data5/', views.Demo5APIView.as_view()),
]

views視圖

from django.shortcuts import render
# Create your views here.
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, IsAdminUser

#用戶的認證和權限識別
class Demo1APIView(APIView):
    #只允許登錄後的用戶訪問
    permission_classes = [IsAuthenticated]
    def get(self, request):
        #個人中心
        return Response("個人中心")

class Demo2APIView(APIView):
    #只允許管理員訪問
    permission_classes = [IsAdminUser]
    def get(self, request):
        #個人中心2
        return Response("個人中心2")

# 自定義權限
from rest_framework.permissions import BasePermission

class MyPermission(BasePermission):
    def has_permission(self, request, view):
        """
        針對訪問視圖進行權限判斷,必須使用xiaoming用戶
        :param request: 本次操作的http請求對象
        :param view:  本次訪問路由對應的視圖對象
        :return:
        """
        if request.user.username == "xiaoming":
            return True
        return False

class Demo3APIView(APIView):
    permission_classes = [MyPermission]

    def get(self, request):
        """個人中心3"""
        return Response("個人中心3")

# 限流
from rest_framework.throttling import UserRateThrottle, AnonRateThrottle
class Demo4APIView(APIView):
    throttle_classes = [UserRateThrottle, AnonRateThrottle]  # 全局配置後,這裡就不用指定
    def get(self, request):
        """投票頁面"""
        return Response("投票頁面")

# 過濾
from rest_framework.generics import GenericAPIView, ListAPIView
from students.models import Student
from opt.serializers import StudentModelSerializer
from django_filters.rest_framework import DjangoFilterBackend
# 'django_filters.rest_framework.DjangoFilterBackend'
class Demo5APIView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    filter_backends = [DjangoFilterBackend]  # 全局配置後,這裡就不用指定了。
    filter_fields = ['age', "id"]  # 聲明過濾字段

複製一個序列化類

(drfdemo) root@darren-virtual-machine:~/PycharmProjects/drfdemo/drf_demo# cp collect/serializers.py     opt/

setting設置

REST_FRAMEWORK = {
    # 限流
    'DEFAULT_THROTTLE_CLASSES': (  # 對全局進行設置
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ),
    'DEFAULT_THROTTLE_RATES': {
        'anon': '3/hour',
        'user': '3/minute',
    }
    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}

訪問//127.0.0.1:8000/opt/data5/

 

 點擊過濾器

 

提交

3.5 排序Ordering

對於列表數據,REST framework提供了OrderingFilter過濾器來幫助我們快速指明數據按照指定字段進行排序。

使用方法:

  在類視圖中設置filter_backends,使用rest_framework.filters.OrderingFilter過濾器,REST framework會在請求的查詢字符串參數中檢查是否包含了ordering參數,如果包含了ordering參數,則按照ordering參數指明的排序字段對數據集進行排序。

前端可以傳遞的ordering參數的可選字段值需要在ordering_fields中指明。

 路由配置

from django.urls import path,re_path
from opt import views

urlpatterns = [
    path('auth1/', views.Demo1APIView.as_view()),
    path('auth2/', views.Demo2APIView.as_view()),
    # 自定義權限
    path('auth3/', views.Demo3APIView.as_view()),
    # 限流
    path('auth4/', views.Demo4APIView.as_view()),
    # 過濾
    path('data5/', views.Demo5APIView.as_view()),
    # 排序
    path('data6/', views.Demo6APIView.as_view()),
]

views視圖配置

from django.shortcuts import render
# Create your views here.
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, IsAdminUser

#用戶的認證和權限識別
class Demo1APIView(APIView):
    #只允許登錄後的用戶訪問
    permission_classes = [IsAuthenticated]
    def get(self, request):
        #個人中心
        return Response("個人中心")

class Demo2APIView(APIView):
    #只允許管理員訪問
    permission_classes = [IsAdminUser]
    def get(self, request):
        #個人中心2
        return Response("個人中心2")

# 自定義權限
from rest_framework.permissions import BasePermission

class MyPermission(BasePermission):
    def has_permission(self, request, view):
        """
        針對訪問視圖進行權限判斷,必須使用xiaoming用戶
        :param request: 本次操作的http請求對象
        :param view:  本次訪問路由對應的視圖對象
        :return:
        """
        if request.user.username == "xiaoming":
            return True
        return False

class Demo3APIView(APIView):
    permission_classes = [MyPermission]

    def get(self, request):
        """個人中心3"""
        return Response("個人中心3")

# 限流
from rest_framework.throttling import UserRateThrottle, AnonRateThrottle
class Demo4APIView(APIView):
    throttle_classes = [UserRateThrottle, AnonRateThrottle]  # 全局配置後,這裡就不用指定
    def get(self, request):
        """投票頁面"""
        return Response("投票頁面")

# 過濾
from rest_framework.generics import GenericAPIView, ListAPIView
from students.models import Student
from opt.serializers import StudentModelSerializer
from django_filters.rest_framework import DjangoFilterBackend
# 'django_filters.rest_framework.DjangoFilterBackend'
class Demo5APIView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    filter_backends = [DjangoFilterBackend]  # 全局配置後,這裡就不用指定了。
    filter_fields = ['age', "id"]  # 聲明過濾字段

# 排序
from rest_framework.filters import OrderingFilter


class Demo6APIView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    filter_backends = [DjangoFilterBackend, OrderingFilter]  # 局部配置會覆蓋全局配置
    filter_fields = ['id', "sex"]
    ordering_fields = ['id', "age"]

訪問//127.0.0.1:8000/opt/data6/

點擊過濾器

 

3.6 分頁Pagination

  REST framework提供了分頁的支持。

  我們可以在配置文件中設置全局的分頁方式,如:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS':  'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 100  # 每頁數目
}

 也可通過自定義Pagination類,來為視圖添加不同分頁行為。在視圖中通過pagination_clas屬性來指明。

  opt下的urls.py
from django.urls import path,re_path
from opt import views

urlpatterns = [
    path('auth1/', views.Demo1APIView.as_view()),
    path('auth2/', views.Demo2APIView.as_view()),
    # 自定義權限
    path('auth3/', views.Demo3APIView.as_view()),
    # 限流
    path('auth4/', views.Demo4APIView.as_view()),
    # 過濾
    path('data5/', views.Demo5APIView.as_view()),
    # 排序
    path('data6/', views.Demo6APIView.as_view()),
    # 分頁
    path('data7/', views.Demo7APIView.as_view()),
]

views視圖文件

from django.shortcuts import render
# Create your views here.
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, IsAdminUser

#用戶的認證和權限識別
class Demo1APIView(APIView):
    #只允許登錄後的用戶訪問
    permission_classes = [IsAuthenticated]
    def get(self, request):
        #個人中心
        return Response("個人中心")

class Demo2APIView(APIView):
    #只允許管理員訪問
    permission_classes = [IsAdminUser]
    def get(self, request):
        #個人中心2
        return Response("個人中心2")

# 自定義權限
from rest_framework.permissions import BasePermission

class MyPermission(BasePermission):
    def has_permission(self, request, view):
        """
        針對訪問視圖進行權限判斷,必須使用xiaoming用戶
        :param request: 本次操作的http請求對象
        :param view:  本次訪問路由對應的視圖對象
        :return:
        """
        if request.user.username == "xiaoming":
            return True
        return False

class Demo3APIView(APIView):
    permission_classes = [MyPermission]

    def get(self, request):
        """個人中心3"""
        return Response("個人中心3")

# 限流
from rest_framework.throttling import UserRateThrottle, AnonRateThrottle
class Demo4APIView(APIView):
    throttle_classes = [UserRateThrottle, AnonRateThrottle]  # 全局配置後,這裡就不用指定
    def get(self, request):
        """投票頁面"""
        return Response("投票頁面")

# 過濾
from rest_framework.generics import GenericAPIView, ListAPIView
from students.models import Student
from opt.serializers import StudentModelSerializer
from django_filters.rest_framework import DjangoFilterBackend
# 'django_filters.rest_framework.DjangoFilterBackend'
class Demo5APIView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    filter_backends = [DjangoFilterBackend]  # 全局配置後,這裡就不用指定了。
    filter_fields = ['age', "id"]  # 聲明過濾字段

# 排序
from rest_framework.filters import OrderingFilter


class Demo6APIView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    filter_backends = [DjangoFilterBackend, OrderingFilter]  # 局部配置會覆蓋全局配置
    filter_fields = ['id', "sex"]
    ordering_fields = ['id', "age"]

#分頁
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination

"""1. 自定義分頁器,定製分頁的相關配置"""
"""
# 頁碼分頁  PageNumberPagination
前端訪問形式:GET  //127.0.0.1:8000/opt/data7/?page=4

page=1   limit 0,10
page=2   limit 10,20

# 偏移量分頁  LimitOffsetPagination
前端訪問形式:GET  //127.0.0.1:8000/opt/data7/?start=4&size=3

start=0  limit 0,10
start=10 limit 10,10
start=20 limit 20,10
"""


class StandardPageNumberPagination(PageNumberPagination):
    """分頁相關配置"""
    page_query_param = "page"          # 設置分頁頁碼關鍵字名
    page_size = 3                      # 設置每頁顯示數據條數
    page_size_query_param = "size"     # 設置指定每頁大小的關鍵字名
    max_page_size = 5                  # 設置每頁顯示最大值


class StandardLimitOffsetPagination(LimitOffsetPagination):
    default_limit = 2                  # 默認限制,默認值與PAGE_SIZE設置一致
    limit_query_param = "size"         # limit參數名
    offset_query_param = "start"       # offset參數名
    max_limit = 5                      # 最大limit限制


class Demo7APIView(ListAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer
    # 分頁
    # 頁碼分頁類
    pagination_class = StandardPageNumberPagination
    # 偏移量分頁類
    # pagination_class = StandardLimitOffsetPagination

訪問//127.0.0.1:8000/opt/data7/

 

訪問//127.0.0.1:8000/opt/data7/?page=1&size=8,就是每一頁顯示8個數據

但是只顯示五個,是在代碼設置最大顯示5個,當設置顯示8個時,不會生效,只會顯示5個


 

參考://www.cnblogs.com/Michael–chen/p/11222143.html,老男孩教育://www.oldboyedu.com/