欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

drf-03-2个视图基类(APIView,GenericAPIView)、5个视图扩展类、GenericAPIView的视图子类、视图集基类ViewSet、常用视图集父类、路由Routers

程序员文章站 2022-07-12 11:17:55
...

一、视图

1. 2个视图基类

settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
    'rest_framework',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'drf02',
        'HOST':'127.0.0.1',
        'PORT':3306,
        'USER':'root',
        'PASSWORD':'123456'
    }
}

同名文件夹下总路由

urls.py

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('app01/', include('app01.urls')),
]

创建的应用app01下

models.py

from django.db import models

# Create your models here.
class Student(models.Model):
    # 模型字段
    name = models.CharField(max_length=100,verbose_name="姓名",help_text='提示文本:不能为空')
    sex = models.BooleanField(default=1,verbose_name="性别")
    age = models.IntegerField(verbose_name="年龄")
    class_null = models.CharField(max_length=5,verbose_name="班级编号")
    description = models.TextField(max_length=1000,verbose_name="个性签名")

    class Meta:
        db_table="tb_student"
        verbose_name = "学生"
        verbose_name_plural = verbose_name

在同名文件的__init__下:
import pymysql
pymysql.install_as_MySQLdb()
创建数据库
执行数据库迁移指令

在应用下创建序列化器

serializers.py

from app01 import models
from rest_framework import serializers

class StudentSerializer(serializers.ModelSerializer):

    class Meta:
        model = models.Student
        fields = '__all__'
        extra_kwargs = {
            'id':{'read_only':True},
            'age':{'write_only':True},
        }


class Student2Serializer(serializers.ModelSerializer):

    class Meta:
        model = models.Student
        fields = ['name','class_null']
        extra_kwargs = {
            'id':{'read_only':True},
            'age':{'write_only':True},
        }

(1)APIView

在应用下的视图中:

views.py

from django.shortcuts import render

# Create your views here.

from rest_framework.views import APIView
from app01 import models
from .serializers import StudentSerializer,Student2Serializer
from rest_framework.response import Response
from rest_framework import status

class Students1View(APIView):
    # 获取所以数据接口
    def get(self,request):
        all_data = models.Student.objects.all()
        serializer = StudentSerializer(instance=all_data,many=True)
        return Response(serializer.data)

    # 添加一条记录的接口
    def post(self,request):
        data = request.data
        serializer = StudentSerializer(data=data)
        if serializer.is_valid():
            instance = serializer.save()  # instance 为添加的新纪录对象
            serializer = StudentSerializer(instance=instance)

            return Response(serializer.data,status=status.HTTP_204_NO_CONTENT)

        else:
            print(serializer.errors)

class Student1View(APIView):

    # 获取单条记录
    def get(self,request,pk):
        stu_obj = models.Student.objects.get(pk=pk)
        serializer = StudentSerializer(instance=stu_obj)
        return Response(serializer.data)

    # 更新单条记录
    def put(self,request,pk):
        stu_obj = models.Student.objects.get(pk=pk)
        data = request.data
        serializer = StudentSerializer(instance=stu_obj,data=data,partial=True)
        if serializer.is_valid():
            instance = serializer.save()
            serializer = StudentSerializer(instance=instance)

            return Response(serializer.data)
        else:
            print(serializer.errors)

    # 删除单条记录

    def delete(self,request,pk):
        models.Student.objects.get(pk=pk).delete()
        return Response(None,status=status.HTTP_204_NO_CONTENT)

urls.py

from django.contrib import admin
from django.urls import path,re_path
from app01 import views


urlpatterns = [
    path('students1/', views.Students1View.as_view()),
    re_path('students1/(?P<pk>\d+)/', views.Student1View.as_view()),

]

runserver设置:

drf-03-2个视图基类(APIView,GenericAPIView)、5个视图扩展类、GenericAPIView的视图子类、视图集基类ViewSet、常用视图集父类、路由Routersdrf-03-2个视图基类(APIView,GenericAPIView)、5个视图扩展类、GenericAPIView的视图子类、视图集基类ViewSet、常用视图集父类、路由Routersdrf-03-2个视图基类(APIView,GenericAPIView)、5个视图扩展类、GenericAPIView的视图子类、视图集基类ViewSet、常用视图集父类、路由Routers

运行图如下:

drf-03-2个视图基类(APIView,GenericAPIView)、5个视图扩展类、GenericAPIView的视图子类、视图集基类ViewSet、常用视图集父类、路由Routersdrf-03-2个视图基类(APIView,GenericAPIView)、5个视图扩展类、GenericAPIView的视图子类、视图集基类ViewSet、常用视图集父类、路由Routers
简单总结:
	 1 获取一个数据,传instance参数
	   获取多条数据,传instance,many=True参数
	 2 更新数据,传instance和data参数
	   部分字段更新,可以增加partial=True参数
	 3 添加数据,传data参数
	 4 删除数据,不需要使用序列化器
(2)GenericAPIView

  继承自APIVIew,主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法支持。通常在使用时,可搭配一个或多个Mixin扩展类。

提供的关于序列化器使用的属性与方法

①属性:

  • serializer_class 指明视图使用的序列化器

②方法:

  • get_serializer_class(self)

    当出现一个视图类中调用多个序列化器时,那么可以通过条件判断在get_serializer_class方法中通过返回不同的序列化器类名就可以让视图方法执行不同的序列化器对象了。

  • get_serializer(self, *args, **kwargs)
    返回序列化器对象,主要用来提供给Mixin扩展类使用,如果我们在视图中想要获取序列化器对象,也可以直接调用此方法。
    注意,该方法在提供序列化器对象的时候,会向序列化器对象的context属性补充三个数据:request、format、view,这三个数据对象可以在定义序列化器时使用。

    • request 当前视图的请求对象
    • view 当前请求的类视图对象
    • format 当前请求期望返回的数据格式

提供的关于数据库查询的属性与方法

①属性:

  • queryset 指明使用的数据查询集

② 方法:

  • get_queryset(self)

    返回视图使用的查询集,主要用来提供给Mixin扩展类使用,是列表视图与详情视图获取数据的基础,默认返回queryset属性,可以重写。

  • get_object(self)
    返回详情视图所需的模型类数据对象,主要用来提供给Mixin扩展类使用。
    在视图中可以调用该方法获取详情信息的模型类对象。
    若详情访问的模型类对象不存在,会返回404。

views.py

from rest_framework.generics import GenericAPIView


class Students2View(GenericAPIView):
    queryset = models.Student.objects.all()  # 必须要指定的
    serializer_class = StudentSerializer  # 选填的

    # 通过get_serializer_class来控制不同条件下,使用不同的序列化器类
    def get_serializer_class(self):
        if self.request.method == 'GET':
            return Student2Serializer
        else:
            return StudentSerializer

    # 获取所有数据接口
    def get(self,request):
        serializer = self.get_serializer(instance=self.get_queryset(), many=True)
        return Response(serializer.data)

        # 添加一条记录的接口
    def post(self, request):
        data = request.data
        serializer = self.get_serializer(data=data)
        if serializer.is_valid():
            instance = serializer.save()
            serializer = self.get_serializer(instance=instance)

            return Response(serializer.data, status=status.HTTP_201_CREATED)

        else:
            print(serializer.errors)
            return Response({'error': '字段错误'})

class Student2View(GenericAPIView):
    queryset = models.Student.objects.all()
    serializer_class = StudentSerializer

    # 获取单条记录
    def get(self, request, pk):

        serializer = self.get_serializer(instance=self.get_object())
        return Response(serializer.data)

    # 更新单条记录
    def put(self, request, pk):

        data = request.data
        serializer = self.get_serializer(instance=self.get_object(), data=data, partial=True)
        if serializer.is_valid():
            # print('>>>',serializer.data)  #在save方法之前,不能调用data属性,serializer.data
            instance = serializer.save()  # instance为添加的新纪录对象
            print(serializer.data)  # 之后可以看
            serializer = self.get_serializer(instance=instance)

            return Response(serializer.data)
        else:
            print(serializer.errors)

    # 删除单条记录

    def delete(self, request, pk):

        models.Student.objects.get(pk=pk).delete()
        return Response(None, status=status.HTTP_204_NO_CONTENT)
        

urls.py

    
    path('students2/', views.Students2View.as_view()),
    re_path('students2/(?P<pk>\d+)/', views.Student2View.as_view()),
    

2. 5个视图扩展类

ListModelMixin、CreateModelMixin、RetrieveModelMixin、UpdateModelMixin、DestroyModelMixin

(1)ListModelMixin

获取多条数据的 列表视图扩展类,提供list(request, *args, **kwargs)方法快速实现列表视图,返回200状态码。

(2)CreateModelMixin

添加数据的创建视图扩展类,提供create(request, *args, **kwargs)方法快速实现创建资源的视图,成功返回201状态码。

(3)RetrieveModelMixin

获取单条数据,详情视图扩展类,提供retrieve(request, *args, **kwargs)方法,可以快速实现返回一个存在的数据对象。如果存在,返回200, 否则返回404。

(4)UpdateModelMixin

更新视图扩展类,提供update(request, *args, **kwargs)方法,可以快速实现更新一个存在的数据对象。
同时也提供partial_update(request, *args, **kwargs)方法,可以实现局部更新。
成功返回200,序列化器校验数据失败时,返回400错误。

(5)DestroyModelMixin

删除视图扩展类,提供destroy(request, *args, **kwargs)方法,可以快速实现删除一个存在的数据对象。成功返回204,不存在返回404。

views.py

############基于视图扩展类mixins的接口########################
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin


class Students3View(GenericAPIView,ListModelMixin,CreateModelMixin):
    queryset = models.Student.objects.all()  #必须要指定的
    serializer_class = StudentSerializer  #选填的

    # 获取所有数据接口
    def get(self, request):
        return self.list(request)

    # 添加一条记录的接口
    def post(self, request):
        return self.create(request)

class Student3View(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
    queryset = models.Student.objects.all()
    serializer_class = StudentSerializer

    # 获取单条记录
    def get(self, request, pk):
        return self.retrieve(request, pk)

    # 更新单条记录
    def put(self, request, pk):

        return self.update(request, pk)

    # 删除单条记录

    def delete(self, request, pk):
        return self.destroy(request, pk)

urls.py


    path('students3/', views.Students3View.as_view()),
    re_path('students3/(?P<pk>\d+)/', views.Student3View.as_view()),
    

3. GenericAPIView的视图子类

(1)CreateAPIView

提供 post 方法
继承自: GenericAPIView、CreateModelMixin

(2)ListAPIView

提供 get 方法
继承自:GenericAPIView、ListModelMixin

(3)RetrieveAPIView

提供 get 方法
继承自: GenericAPIView、RetrieveModelMixin

(4)DestoryAPIView

提供 delete 方法
继承自:GenericAPIView、DestoryModelMixin

(5)UpdateAPIView

提供 put 和 patch 方法
继承自:GenericAPIView、UpdateModelMixin

(6)RetrieveUpdateAPIView

提供 get、put、patch方法
继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin

(7)RetrieveUpdateDestoryAPIView

提供 get、put、patch、delete方法
继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin
views.py

############基于视图子类的接口#################
from rest_framework.generics import ListAPIView,CreateAPIView,RetrieveAPIView,UpdateAPIView,DestroyAPIView

class Students4View(ListAPIView,CreateAPIView):
    queryset = models.Student.objects.all()  #必须要指定的
    serializer_class = StudentSerializer  #选填的


class Student4View(RetrieveAPIView,UpdateAPIView,DestroyAPIView):
    queryset = models.Student.objects.all()
    serializer_class = StudentSerializer

urls.py

    path('students4/', views.Students4View.as_view()),
    re_path('students4/(?P<pk>\d+)/', views.Student4View.as_view()),

4. 视图集基类ViewSet

使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中:

  • list() 提供一组数据
  • retrieve() 提供单个数据
  • create() 创建数据
  • update() 保存数据
  • destory() 删除数据

ViewSet视图集类不再实现get()、post()等方法,而是实现动作 action 如 list() 、create() 等。
视图集只在使用as_view()方法的时候,才会将action动作与具体请求方式对应上。
views.py

from rest_framework.viewsets import ViewSet

class Students5View(ViewSet):
    # 获取所有数据接口
    def get_all_student(self,request):  # action
        all_data = models.Student.objects.all()
        serializer = StudentSerializer(instance=all_data,many=True)
        return Response(serializer.data)

    # 添加一条记录的接口
    def add_student(self,request):
        data = request.data
        serializer = StudentSerializer(data=data)
        if serializer.is_valid():
            instance = serializer.save()  #instance为添加的新纪录对象
            serializer = StudentSerializer(instance=instance)

            return Response(serializer.data,status=status.HTTP_201_CREATED)

        else:
            print(serializer.errors)

    def get_one(self,request,pk):
        stu_obj = models.Student.objects.get(pk=pk)
        serializer = StudentSerializer(instance=stu_obj)
        return Response(serializer.data)

urls.py

    path('students5/', views.Students5View.as_view({'get':'get_all_student','post':'add_student'})),
    re_path('students5/(?P<pk>\d+)/', views.Students5View.as_view({'get':'get_one'})),

5. 常用视图集父类

1) ViewSet

  继承自APIViewViewSetMixin,作用也与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()时传入字典的映射处理工作的同时,还提供了GenericAPIView提供的基础方法,可以直接搭配Mixin扩展类使用。

3)ModelViewSet

  继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。

views.py

from rest_framework.viewsets import ViewSet,GenericViewSet

class Students6View(GenericViewSet):
    queryset = models.Student.objects.all()
    serializer_class = StudentSerializer

    # 获取所有数据接口
    def get_all_student(self,request):  # action
        all_data = self.get_queryset()
        serializer = self.get_serializer(instance=all_data,many=True)
        return Response(serializer.data)

    # 添加一条记录的接口
    def add_student(self,request):
        data = request.data
        serializer = StudentSerializer(data=data)
        if serializer.is_valid():
            instance = serializer.save()  #instance为添加的新纪录对象
            serializer = StudentSerializer(instance=instance)

            return Response(serializer.data,status=status.HTTP_201_CREATED)

        else:
            print(serializer.errors)

    def get_one(self,request,pk):
        stu_obj = models.Student.objects.get(pk=pk)
        serializer = StudentSerializer(instance=stu_obj)
        return Response(serializer.data)
from rest_framework.viewsets import ViewSet,GenericViewSet
from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin

class Students7View(GenericViewSet,ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
    queryset = models.Student.objects.all()
    serializer_class = StudentSerializer


    # 获取所有数据接口
    def get_all_student(self,request):  # action
        return self.list(request)

    # 添加一条记录的接口
    def add_student(self,request):

        return self.create(request)

    def get_one(self,request,pk):
        return self.retrieve(request,pk)

    def update_one(self,request,pk):
        return self.update(request,pk)

    def delete_one(self,request,pk):
        return self.destroy(request,pk)
from rest_framework.viewsets import ViewSet,GenericViewSet,ModelViewSet
from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
class Students8View(GenericViewSet,ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
    queryset = models.Student.objects.all()
    serializer_class = StudentSerializer

urls.py

    path('students6/', views.Students6View.as_view({'get':'get_all_student','post':'add_student'})),
    re_path('students6/(?P<pk>\d+)/', views.Students6View.as_view({'get':'get_one'})),
    
    path('students7/', views.Students7View.as_view({'get':'get_all_student','post':'add_student'})),
    re_path('students7/(?P<pk>\d+)/', views.Students7View.as_view({'get':'get_one','put':'update_one','delete':'delete_one'})),

    path('students8/', views.Students8View.as_view({'get':'list','post':'create'})),
    re_path('students8/(?P<pk>\d+)/', views.Students8View.as_view({'get':'retrieve','put':'update','delete':'destroy'})),
    re_path('students8/login/', views.Students8View.as_view({'get':'login',})),

6. 视图集中定义附加action动作

views.py

from rest_framework.decorators import action

from rest_framework.viewsets import ModelViewSet
class Students8View(ModelViewSet):
    queryset = models.Student.objects.all()
    serializer_class = StudentSerializer
    # 
    
    def login(self,request,pk): # 这个就可以称为自定义的action动作
        return Response({'msg':'success'})

二、路由Routers

对于视图集ViewSet,除了可以自己手动指明请求方式与动作action之间的对应关系外,还可以使用Routers来帮助我们快速实现路由信息。
REST framework提供了两个router:

  • SimpleRouter
  • DefaultRouter
1.使用

urls.py

from rest_framework import routers

# router = routers.DefaultRouter()
router = routers.SimpleRouter()
router.register('dd',views.Students8View)
urlpatterns += router.urls

print(urlpatterns)
2.视图集中附加action的声明

action装饰器可以接收两个参数:

  • methods: 声明该action对应的请求方式,列表传递
  • detail: 声明该action的路径是否与单一资源对应

views.py

from rest_framework.decorators import action

from rest_framework.viewsets import ModelViewSet
class Students8View(ModelViewSet):
    queryset = models.Student.objects.all()
    serializer_class = StudentSerializer
    
    @action(methods=['get'], detail=True) #detail=True自动生成带参数的路径,False生成不带参数的路径
    def login(self,request,pk):
        return Response({'msg':'success'})