首页 > 其他分享 >drf3

drf3

时间:2023-02-02 19:34:09浏览次数:42  
标签:drf3 return ser self request 序列化 data

今日内容概要

  • APIView执行流程
  • Request对象源码分析
  • 序列化器介绍和快速使用
  • 反序列化
  • 基于序列化器编写5个接口
  • 反序列化的校验

今日内容详细

APIView执行流程

'''基于APIView+JsonResponse编写接口'''
drf提供了一个类 之后使用drf编写视图类 都是集成这个类及其子类 APIView本身就是继承了django原生的View
from rest_framework.views import APIView

class BookView(APIView):
    def get(self, request):
        books = Book.objects.all()
        book_list = []
        for book in books:
            book_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
        return JsonResponse(book_list, safe=False)

'''基于APIView+Response编写接口'''
from rest_framework.response import Response

class BookView(APIView):
    def get(self, request):
        books = Book.objects.all()
        book_list = [{'name': book.name, 'price': book.price, 'publish': book.publish} for book in books]
        return Response(book_list) # Response无论是列表还是字典都可以被序列化

'''APIView的执行流程'''
路由 path('api/v1/books/', views.BookView.as_view()),
当请求来了并且匹配成功--->执行views.BookView.as_view()--->自身类并没有as_view()函数 父类中有 那么执行父类的as_view() 也就是APIView中的as_view()

    @classmethod
    def as_view(cls, **initkwargs):
        # 执行父类View中的as_view 返回的是闭包函数view的内存地址
        view = super().as_view(**initkwargs)
        # csrf_exempt是将csrf认证去除 原本是一个装饰器
        # 相当于是将BookView中所有方法都装上了这个装饰器
        return csrf_exempt(view)
执行csrf_exempt(view)也就是加了装饰器的view函数--->view函数返回的是self.dispatch此时的self是视图类的对象--->视图类并没有dispatch方法去父类APIView中找--->查看源码发现有
    def dispatch(self, request, *args, **kwargs):
        # 将老的request传入initialize_request方法 并将结果赋值给request 具体看图
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        try:
            # 执行了三大认证(认证 频率 权限) 用的是新的request
            self.initial(request, *args, **kwargs)
            # 下面操作流程与原本一致
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed
            # 视图类中使用的request也是新的
            response = handler(request, *args, **kwargs)

        except Exception as exc:
            # 在执行视图类中方法和认证过程中如果出现了异常 都能捕获到--->全局异常捕获
            response = self.handle_exception(exc)

        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response
    
    
总结:
	1.APIView去除了所有的csrf认证
	2.使用了新的request 也就是Request类的对象 不再是django原生的request
	3.执行视图类的方法之前都会执行3大认证
	4.如果在执行视图类方法和3大认证出现了错误 会被捕获--->全局异常捕获

image

Request对象源码分析

from rest_framework.request import Request

查看Request源码
我们发现新的request也可以执行request.method方法 但是源码中并没有 可以联想到魔法方法__getattr__ 点不存在的名字的时候执行该方法下的代码 源码中的确有该方法
    def __getattr__(self, attr):
        try:
            # 可以发现是利用的反射 使用老的request取得想要的属性
            return getattr(self._request, attr)
        except AttributeError:
            return self.__getattribute__(attr)

request.data---->这是个方法 被伪装成了数据属性
	主要作用是 之后无论post put等等放在body中的数据都是从该方法中取到 取出来的就是字典 无论是哪种编码格式

request.query_params---->这是个方法 被伪装成了数据属性
	get请求携带的数据 都从这儿取
	查询参数 restful规范请求地址中带查询参数

request.FILES---->这是个方法 被伪装成了数据属性
	前端提交过来的文件 从这儿取

    
Request类总结
	1.新的request用起来和之前的一模一样 当新的某些方法取不到 就会通过__getattr__方法取旧的
	2.request.data 无论什么编码 什么请求方式 只要是body中的数据 都从这里取 以字典形式
	3.request.query_params 就相当于原来的request.GET--->request._request.GET
	4.上传的文件从request.FILES中取

序列化器介绍和快速使用

再写接口的时候 需要序列化和反序列化 并且反序列化的过程中需要做数据的校验 drf中直接提供了固定的写法 只需要按照固定写法使用 就可以完成上面的三个需求

提供了两个类 Serializer和ModelSerializer
	之后只需要写自己的类 继承drf提供的序列化类 使用其中的某些方法就行

创建一个serializer的py文件 并写一个序列化类
from rest_framework import serializers

class BookSerizlizer(serializers.Serializer):
    # 编写需要序列化的字段 
    name = serializers.CharField()	# 编写方式大致与models下的类是对应的
    price = serializers.CharField()

views.py下
class BookView(APIView):
    def get(self, request):
        books = Book.objects.all()
        # 使用序列化类来完成
        # instance需要接收要序列化的数据
        # many=True 只要是queryset对象就要传 单个对象就不用传
        ser = BookSerizlizer(instance=books, many=True)
        return Response(ser.data)	# 无论是列表还是字典都可以被序列化
        # 序列化类产生的对象.data取到的是序列化后的数据

序列化单条的话类似 只需要稍微修改视图类即可 可以重新写一个视图类 或者结合在一起
    def get(self, request, *args, **kwargs):
        if kwargs:
            book = Book.objects.filter(**kwargs).first()
            ser = BookSerializers(instance=book)
            return Response(ser.data)
        books = Book.objects.all()
        ser = BookSerializers(instance=books, many=True)
        return Response(ser.data)
路由层
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('api/v1/books/', views.BookView.as_view()),
        path('api/v1/books/<int:pk>/', views.BookView.as_view()),
    ]

反序列化

'''反序列化类的新增'''

序列化类中
class BookSerializer(serializers.Serializer):
    name = serializers.CharField()
    price = serializers.CharField()
    publish = serializers.CharField()

    def create(self, validated_data):
        # 保存的逻辑
        # validated_data 校验过后的数据 {name,price,publish}
        # 保存到数据库
        book = Book.objects.create(**validated_data)
        # 一定要返回新增的对象
        return book

视图类中
class BookView(APIView):
    def post(self, request):
        # requset.data  # 前端提交的要保存的数据----》校验数据---》存
        ser = BookSerializer(data=request.data)  # 把前端传入的要保存的数据,给data参数
        # 校验数据
        if ser.is_valid():
            # 保存---->需要自己写,要在序列化类BookSerializer中写create方法
            ser.save()  # 调用ser.save,自动触发自己写的create 并保存
            return Response({'code': 100, 'msg': '新增成功', 'result': ser.data})
        return Response({'code': 101, 'msg': ser.errors})

'''反序列化类的修改'''
序列化类中
    def update(self, instance, validated_data):
            # instance 要修改的对象
            # validated_data 校验过后的数据
            instance.name = validated_data.get('name')
            instance.price = validated_data.get('price')
            instance.publish = validated_data.get('publish')
            instance.save()  # orm的单个对象,修改了单个对象的属性,只要调用对象.save,就能把修改保存到数据库

            return instance  # 不要忘了吧修改后的对象,返回

基于序列化器编写5个接口

class BookView(APIView):

    def get(self, request, *args, **kwargs):
        if kwargs:
            book = Book.objects.filter(**kwargs).first()
            ser = BookSerializers(instance=book)
            return Response(ser.data)
        books = Book.objects.all()
        ser = BookSerializers(instance=books, many=True)
        return Response(ser.data)

    def post(self, request, *args, **kwargs):
        ser = BookSerializers(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '新增成功', 'result': ser.data})
        return Response({'code': 101, 'msg': ser.errors})

    def put(self, request, *args, **kwargs):
        book = Book.objects.filter(**kwargs).first()
        ser = BookSerializers(data=request.data, instance=book)
        if ser.is_valid():
            ser.save()
            return Response({'code': 100, 'msg': '修改成功', 'result': ser.data})
        return Response({'code': 101, 'msg': ser.errors})

    def delete(self, request, *args, **kwargs):
        Book.objects.filter(**kwargs).delete()
        return Response({'code': 102, 'msg': '删除成功'})

反序列化的校验

序列化类反序列化有数据校验功能 类似于forms组件

class BookSerializer(serializers.Serializer):

    # 局部钩子
    # 反序列化校验的局部钩子 ,名字不能以sb开头
    def validate_name(self, name):
        # 校验name是否合法
        if name.startswith('sb'):
            # 校验不通过,抛异常
            raise ValidationError('不能以sb开头')
        else:
            return name

    # 全局钩子
    def validate(self, attrs):
        # 校验过后的数据,书名跟出版社名字不能一致
        if attrs.get('name') == attrs.get('publish'):
            raise ValidationError('书名跟出版社名字不能一致')
        else:
            return attrs

标签:drf3,return,ser,self,request,序列化,data
From: https://www.cnblogs.com/lzjjjj/p/17087189.html

相关文章