Django Rest_Framework之视图类和通用视图类以及子类

一.反序列化器保存数据

前面的验证数据成功后,我们可以使用序列化器来完成数据反序列化的过程.这个过程可以把数据转成模型类对象.

可以通过实现create()和update()两个方法来实现。
1.添加数据:

class BooksView(View):

    def get(self,request):

        # 添加数据
        data_dict = {
            'title': 'test1213',
            'pub_data': '2019-10-11',
            # 'read':-1,  模拟失败
            'read': 2000,
            'comment': 400,
        }

        serializers = BookSerializers(data=data_dict)
        serializers.is_valid(raise_exception=True)
        # drf不建议在这里写 最好写在序列化器类里面
        # Student.objects.create(**serializers.validated_data)  
        serializers.save()  # 保存数据
        return JsonResponse(serializers.data)
        # 调用序列化内部保存数据的方法[自动调用create或者update]
        # 在源码save方法中 如果初始化序列化器时以是否传递了instance参数作为判断依据
        # 如果传递了instance 则save方法中调用update进行更新数据
        # 如果没有传递instance 则save方法中调用create进行数据创建
        # 都需要在序列化器类中定义好这两个方法
		
		

保存数据源码:

	在源码save方法中 如果初始化序列化器时以是否传递了instance参数作为判断依据
    如果传递了instance 则save方法中调用update进行更新数据
    如果没有传递instance 则save方法中调用create进行数据创建
    都需要在序列化器类中定义好这两个方法
if self.instance is not None:
    self.instance = self.update(self.instance, validated_data)
    assert self.instance is not None, (
        '`update()` did not return an object instance.'
    )
else:
    self.instance = self.create(validated_data)
    assert self.instance is not None, (
        '`create()` did not return an object instance.'
    )

2.更新数据:

class BooksView(View):


	def get(self,request):
	    # 更新数据
	    data_dict = {
	        'title': 'test',
	        'pub_data': '2019-10-11',
	        # 'read':-1,  模拟失败
	        'read': 2000,
	        'comment': 400,
	    }
	
	    pk = 9
	    book_obj = Book.objects.get(pk=pk)
	
	    serializers = BookSerializers(instance=book_obj,data=data_dict)
	    serializers.is_valid(raise_exception=True)
	    serializers.save()
	    return JsonResponse(serializers.data)

序列化器类中:

# 保存数据
# 两个方法:内置的

# 第一种 create
def create(self, validated_data):
    '''添加数据'''
    # validated_data.pop  删除数据
    instance = models.Book.objects.create(**validated_data)
    return instance


# 第二种 update
def update(self, instance, validated_data):
    '''修改数据'''
    instance.title = validated_data.get('title')
    instance.pub_data = validated_data.get('pub_data')
    instance.read = validated_data.get('read')
    instance.comment = validated_data.get('comment')
    # 下面的save是调用了ORM中提供给模型保存数据的save 不是序列化器中的save
    instance.save()

    return instance

二.模型类序列化器类

如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。

ModelSerializer与常规的Serializer相同,但提供了:

  • 基于模型类自动生成一系列字段
  • 基于模型类自动为Serializer生成validators,比如unique_together
  • 包含默认的create()和update()的实现

定义:

  • model 指明参照哪个模型类
  • fields 指明为模型类的哪些字段生成 __all__表名包含所有字段,也可以写明具体哪些字段
  • 使用exclude可以明确排除掉哪些字段
  • 可以通过read_only_fields指明只读字段,即仅用于序列化输出的字段
  • 可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数

定义模型类:

from rest_framework import serializers

class BookModelSerializers(serializers.ModelSerializer):

    class Meta:

        model = models.Book
        fields = '__all__'
        # exclude = ['xx'] # 排除

        extra_kwargs = {
            'title':{'error_messages':{'max_length':'不能大于30个字符!!!'}}
        }

视图中:

class BooksModelView(View):

    # 展示所有的数据
    def get1(self,request):
        # 序列化展示数据
        book_list = Book.objects.all()
        serializers = BookModelSerializers(instance=book_list,many=True)
        return JsonResponse(serializers.data,safe=False)

    # 展示一条数据
    def get2(self, request,pk):
        # 序列化展示数据
        book_list = Book.objects.get(pk=pk)
        serializers = BookModelSerializers(instance=book_list)
        return JsonResponse(serializers.data)

    def get(self,request):
        '''反序列化校验数据'''
        data_dict = {
            'title': 'test',
            'pub_data': '2019-10-11',
            # 'read':-1,  模拟失败
            'read': 2000,
            'comment': 400,
        }

        serializers = BookModelSerializers(data=data_dict)
        serializers.is_valid(raise_exception=True) # 数据校验
        print(serializers.errors)  # 错误信息
        print(serializers.data)    # 序列化后的数据
        print(serializers.validated_data)  # 正确信息数据
        serializers.save()
        return JsonResponse(serializers.data)

三.DRF中的Request和Response

1.Request:
REST framework 传入视图的request对象不再是Django默认的HttpRequest对象,而是REST framework提供的扩展了HttpRequest类的Request类的对象。

REST framework 提供了Parser解析器类,在接收到request请求后会自动根据Content-Type指明的请求数据类型(如JSON、表单等)将请求数据进行parse解析,解析为类字典[QueryDict]对象保存到Request对象中。

Request对象的数据是自动根据前端发送数据的格式进行解析之后的结果。

无论前端发送的哪种格式的数据,我们都可以以统一的方式读取数据。

常用属性:

.data:
	request.data` 返回解析之后的请求体数据。
	类似于Django中标准的request.POST和request.FILES属性,
	但提供如下特性:
			包含了解析之后的文件和非文件数据
			包含了对POST、PUT、PATCH请求方式解析后的数据
			利用了REST framework的parsers解析器,不仅支持表单类型数据,也支持JSON数据
.query_params:
			request.query_params与Django标准的request.GET相同,只是更换了更正确的名称而已。

2.Response:
REST framework提供了一个响应类Response,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染器对象)成符合前端需求的类型。

REST framework提供了Render 渲染器,用来根据请求头中的Accept(接收数据类型声明)来自动转换响应数据到对应格式。如果前端请求中未进行Accept声明,则会采用默认方式处理响应数据,我们可以通过配置来修改默认响应格式。

构造方式:

Response(data, status=None, template_name=None, headers=None, content_type=None)

data数据不要是render处理之后的数据,只需传递python的内建类型数据即可,REST framework会使用renderer渲染器处理data

data不能是复杂结构的数据,如Django的模型类对象,对于这样的数据我们可以使用Serializer序列化器序列化处理后(转为了Python字典类型)再传递给data参数。

参数说明:
data: 为响应准备的序列化处理后的数据
status: 状态码,默认200
template_name: 模板名称,如果使用HTMLRenderer 时需指明
headers: 用于存放响应头信息的字典
content_type: 响应数据的Content-Type,通常此参数无需传递,REST framework会根据前端所需类型数据来设置该参数。

常用属性:
.data:传给response对象的序列化后,但尚未render处理的数据
.status_code:状态码的数字
.content:经过render处理后的响应数据

示例:

from student.models import Student
from rest_framework.views import APIView
from student.serializers import StudentModelserializers
from rest_framework.response import Response
from rest_framework import status

class StudentView(APIView):

    def get(self, request):
        print(request)  # <rest_framework.request.Request object at 0x000001E46EE90438>  drf的request对象
        print(request._request)  # <WSGIRequest: GET '/testhttpdemo/httpdemo/'> django原生的request
        print(request.query_params) # 获取查询参数  <QueryDict: {'a': ['1']}>
        print(request.data) # 请求体数据
        student_list = Student.objects.all()
        serializers = StudentModelserializers(instance=student_list, many=True)

        return Response(serializers.data,status=status.HTTP_200_OK)  # Response对象

DRF专门封装了状态供我们使用:

from rest_framework import status

四.视图类APIView

APIView是REST framework提供的所有视图的基类,继承自Django的View父类。

APIViewView的不同之处在于:

  • 传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;
  • 视图方法可以返回REST framework的Response对象,视图会为响应数据设置(render)符合前端要求的格式;
  • 任何APIException异常都会被捕获到,并且处理成合适的响应信息;
  • 在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制。

支持定义的属性

  • authentication_classes 列表或元祖,身份认证类
  • permissoin_classes 列表或元祖,权限检查类
  • throttle_classes 列表或元祖,流量控制类

APIView中仍以常规的类视图定义方法来实现get() 、post() 或者其他请求方式的方法。

示例:

from rest_framework.views import APIView
from student.models import Student
from student.serializers import StudentModelserializers
from rest_framework.response import Response
from rest_framework import status


class StudentView(APIView): # 继承APIView

    def get(self, request):

        # 展示数据
        student_list = Student.objects.all()
        serializers = StudentModelserializers(instance=student_list, many=True)
        return Response(serializers.data, status=status.HTTP_200_OK)


    def post(self,request):

        # 添加数据
        data = request.data
        serializers = StudentModelserializers(data=data)
        serializers.is_valid(raise_exception=True)
        serializers.save()
        return Response(serializers.data)

结果:
在这里插入图片描述
可以在rest_framework的settigns.py中看到:
在这里插入图片描述
点击json会返回json类型的数据,不再是rest_framework的api页面,默认是api页面
在这里插入图片描述

四.通用视图类GenericAPIView

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

属性:
**serializer_class:**指明视图使用的序列化器
queryset: 指明使用的数据查询集
方法:
get_queryset(self):
返回视图使用的查询集,主要用来提供给Mixin扩展类使用,是列表视图与详情视图获取数据的基础,默认返回queryset属性
get_object(self):
返回详情视图所需的模型类数据对象,主要用来提供给Mixin扩展类使用。
在试图中可以调用该方法获取详情信息的模型类对象。
get_serializer(self, *args, **kwargs):
返回序列化器对象,主要用来提供给Mixin扩展类使用,如果我们在视图中想要获取序列化器对象,也可以直接调用此方法。

示例:

from rest_framework.generics import GenericAPIView

class StudentGenericAPIView(GenericAPIView):

    # 指明序列化器类
    serializer_class = StudentModelserializers

    # 指明数据查询集
    queryset = Student.objects.all()


    def get(self,request):
        # 展示数据
        serializers = self.serializer_class(instance=self.get_queryset(),many=True)
        return Response(serializers.data)

    def post(self,request):
        # 添加数据
        data = request.data
        serializers = self.serializer_class(data=data)
        serializers.is_valid(raise_exception=True)
        serializers.save()
        return Response(serializers.data)

五.使用GenericAPIView和视图扩展类Mixins进行代码的简写

在drf中提供了五个不同视图扩展类,里面封装了五个不同的http请求方法,用于和GenericAPIView实现代码的简写:

  1. CreateModelMixin[添加一条数据]
  2. ListModelMixin[获取所有数据]
  3. RetrieveModelMixin[获取一条数据]
  4. DestroyModelMixin[删除一条数据]
  5. UpdateModelMixin[更新一条数据]

示例:

from rest_framework.mixins import CreateModelMixin,ListModelMixin

class Student3GenericAPIView(GenericAPIView,CreateModelMixin,ListModelMixin):

    serializer_class = StudentModelserializers
    queryset = Student.objects.all()

    def get(self,request):
        # 展示数据
        return self.list(request)
        
    def post(self,request):
        # 添加数据
        return self.create(request)

可以看到,代码简洁了很多,但是为什么直接可以返回一个list就会展示数据,返回create就会创建数据呢,看一下源码:

展示数据ListModelMixin:
在这里插入图片描述

创建数据CreateModelMixin:
在这里插入图片描述
删除数据:

class Student4GenericAPIView(GenericAPIView,DestroyModelMixin):

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

DestroyModelMixin源码分析:
在这里插入图片描述
首先看get_object:
get_object方法上面定义两个变量:
在这里插入图片描述
在这里插入图片描述
那么这个self.kwargs是在哪里传递进来的呢?
在这里插入图片描述
发现GenericAPIView继承自APIView:
在这里插入图片描述
在这里插入图片描述
但是APIView自己又没有初始化的方法,那么还要考虑self.kwargs的数据是在哪里传进来的,上面刚说到APIView继承View,这个View就是django的View,点进去看一下,下面这张图可以看到这里有初始化方法,并且有kwargs:
在这里插入图片描述
具体的删除流程如下:
1.在View中取出传递进来的参数
2.通过字典取值的方式将传递进来的pk值获取出来,组成一个字典
3.使用视图开展类DestroyModelMixin中的destroy方法将数据删除
4.如果获取不到具体的查询集则抛出Http404

六.GenericAPIView通用视图子类

在上面的使用过程中 都是视图类继承GenericAPIView和视图扩展类Mixins来实现简写的
但是简写的不够彻底 所以在drf中还可以进一步简化,drf基于GenericAPIView和视图扩展类 衍生出了多个视图子类。

  1. CreateAPIView 添加一条数据
  2. ListAPIView 获取所有数据
  3. UpdateAPIView 更新一条数据
  4. RetrieveAPIView 获取一条数据
  5. DestroyAPIView 删除一条数据
  6. RetrieveUpdateDestroyAPIView 获取一条数据 更新一条数据 删除一条数据
  7. RetrieveUpdateAPIView 获取一条数据 更新一条数据
from rest_framework.generics import CreateAPIView,ListAPIView,DestroyAPIView
class Student5GenericAPIView(CreateAPIView,ListAPIView,DestroyAPIView):

    serializer_class = StudentModelserializers
    queryset = Student.objects.all()

这里已经将所有的方法都写好了,和我们上面使用视图扩展类Mixins里面写的代码一样,这里只需要继承视图扩展类的子类就可以全部搞定:
在这里插入图片描述

总结:
APIView:视图基类
GenericAPIView:通用视图类
视图扩展类:mixins 一共五个
视图扩展子类:generics 一共七个

视图扩展类:

ListModelMixin:获取所有数据
CreateModelMixin:创建一条数据
RetrieveModelMixin:获取一条数据
UpdateModelMixin:更新一条数据
DestroyModelMixin:删除一条数据

视图扩展子类:

CreateAPIView 添加一条数据
ListAPIView  获取所有数据
UpdateAPIView 更新一条数据
RetrieveAPIView 获取一条数据
DestroyAPIView 删除一条数据
RetrieveUpdateDestroyAPIView 获取一条数据  更新一条数据 删除一条数据
RetrieveUpdateAPIView 获取一条数据  更新一条数据

猜你喜欢

转载自blog.csdn.net/qq_39253370/article/details/106507393