DRF从入门到精通二(Request源码分析、DRF之序列化、反序列化、反序列化校验、序列化器常用字段及参数、source、定制字段、保存数据)

本文主要对Request对象源码和DRF序列化组件进行分析。在Request对象方面,区分了原生和新生request,指出新request多了data属性。对于DRF序列化组件,介绍了序列化和反序列化步骤、基本使用方法、常用字段和参数,还提及了反序列化的保存、校验以及ModelSerializer的使用。

一、Request对象源码分析

在上一篇博客中最后分析APIView时,我们分析出继承了APIView的视图,以后request都是新的request了,是DRF提供的Request的对象

区分原生request和新生request

	原生request:django.core.handlers.wsgi.WSGIRequest

	新生request:from rest_framework.request import Request

	原生request可以在新生request._request中获取

新的request还能像原来的reqeust一样使用吗

	用起来屎一样的,新的request只是在原来的request基础上添加了一些功能,并不影响基础功能的使用,其本质就是类似装饰器
	 print(request.method)  # get
     print(request.path)  # /movies/
     print(request.GET)   # 原来的get请求提交的参数
     print(request.POST)  # 原来post请求提交的参数

源码片段分析

	'''源码解析之 __init__'''
	从上面区分原生request和新的request中可以知道,老的request对象其实就是在新的内部,request._request中
	'我们先看__init__,它是一个初始化方法,类实例化得到对象时,会执行它,然后会往对象中放数据'
	
	def __init__(self, request, parsers=None, authenticators=None,
                 negotiator=None, parser_context=None):
		
		'''
		传入的request是老的,django原生的request
		放到self._request,self是新的request类的对象
		这里它把传入过来的原request放到这个self._request中,这里的self已经不是视图类了,
		因为这个Request类没有继承任何一个类,它就是它自己,所以这个self是Request
		'''
        self._request = request
        self._data = Empty
        self._files = Empty
        .....

在类内部,以 __开头 __结尾的方法, 在某种情况下会自动调用,他们称之为魔法方法。具体有那些,可以自行搜索,因为所有的类都继承了Object类,所以也可以在Object类中看看,但是不全里面

在这里插入图片描述

	'''源码解析之__getattr__'''
	类中有个魔法方法:__getattr__,对象.属性,属性不存在会触发它的执行
   def __getattr__(self, attr): 如果取的属性不存在会去原生的Django的request对象中取出来
	   try:
 '通过反射,因为这里是self._request所以去Django的request取,能取到就返回,娶不到就执行except代码,如果还取不到则报错'
	        return getattr(self._request, attr)
	    except AttributeError:
	        return self.__getattribute__(attr)
	 '以后用的所有属性或方法,直接用就可以了(通过反射去原来的request中取)' 

以后新的request中多了一个属性data,它会把前端post/put提交的请求体中的数据,都放在request.data中,无论何种编码格式,它都是字典

	data是一个方法,被property装饰了,变成了数据属性用
		-以后body中提交的数据,都从这里取(request.POST)
		-urlencoded,form-data:提交的数据在request.POST中
		-json格式提交的数据,在request.POST中是没有的,它在request.body中
		-现在无论那种格式,都可以直接从request.data中取
	
	request.query_params:get请求提交的参数,以后从这里取
	
	request.FILES:取文件就还是从这个里面取,和之前一样

总结:

	1.新的request跟之前的用法一模一样,如果新的request取不到,它使用__getattr__魔法方法去原生request中取。
		当然原生的也可以直接在新的request中拿到,request._request
	2.新的request中多了data属性,request.data客户端提交的请求体中的数据,无论是什么编码都在request.data中
	3.其他的使用和原生的request一模一样
		request.query_params就是原来的request._request.GET
		上传的文件从request.FILES

	
	'''
	1.原生Django提交数据(post),只能处理urlencoded和form-data编码,从request.POST中取
	2.原生Django提交数据(put),处理不了,需要我们从request.body中取出来进行处理
		分不同编码格式:
			urlencoded------》例:name=lqz&age=19---》使用字符串切割的方式.split
			json----->{'xxx':'xx','yyy':'yy'}--->需要自己进行json.loads反序列化
	3.原生Django不能处理json提交的数据(post/put),需要自己做反序列化
		json----->{'xxx':'xx','yyy':'yy'}--->需要自己进行json.loads反序列化
	4.新的request解决了所有问题:request.data
	'''

二、DRF之序列化组件

	序列化类(组件)可以做的事情:
		1.序列化,QuerySet对象,单个对象做序列化给前端
		2.反序列化数据校验:前端传入数据后校验数据是否合法
		3.反序列化数据保存:前端传入数据,存到数据库中

序列化介绍

  • 在写接口时,需要序列化和反序列化,而且反序列化的过程中要做数据校验,drf直接提供了固定的写法,只需要按照固定写法,只需要按照固定写法使用,就能完成上面的三个需求。
  • 提供了两个类SerializerModelSerializer,编写自定义的类,只需要继承drf提供的序列化类,就可以使用其中的某些方法,也能完成上面的三个需求

序列化类的作用:做序列化、反序列化、反序列化校验

序列化步骤

	1.写一个py文件,叫serializer.py(命名随意)
	2.写一个序列化类,继承serializers.Serializer,
	3.在类中编写需要序列化的字段
		例:name=serializers.CharField()
	4.在视图类中使用,导入models文件中的类books,然后实例化得到对象,对查出来的query对象们,
		对单个对象序列化并传入instance=books参数
		如果query是复数,一定要串many=True,如果query是单个对象,就无需传入many
	5.序列化类对象:ser.data---->字典或列表----->通过Response将json格式字符串返回给前端

序列化组件的基本使用

1.创建一个py文件 ----》serializer.py
	from rest_framework import serializers
	
	class BookSerializer(serializers.Serializer):
	    name = serializers.CharField(max_length=18, min_length=2, required=True)
	    price = serializers.IntegerField(required=True)
	    

2.view.py文件中
	from app01 import models
	from rest_framework.views import APIView
	from rest_framework.response import Response
	from .serializer import BookSerializer
	
	class BookView(APIView):
	    def get(self, request):
	        book_list = models.Book.objects.all()
	        ser = BookSerializer(instance=book_list, many=True)  # 序列化多条需要many=True
	        return Response({
   
   'code': 100, 'msg': '查询成功', 'results': ser.data}) # 无论是列表还是字典都可以序列化

	class BookDetailView(APIView):
	    def get(self, request, pk):
	        book_obj = models.Book.objects.filter(pk=pk).first()
	        ser = BookSerializer(instance=book_obj)
	        if ser.is_valid():
	            return Response({
   
   'code': 100, 'msg': '查询一条成功', 'results': ser})
	        else:
	            return Response(ser.errors)

3.urls.py文件中
	urlpatterns = [
	    path('books/', views.BookView.as_view()),
	    path('books/<int:pk>', views.BookDetailView.as_view()),
	]

在这里插入图片描述

反序列化基本使用

反序列化过程:新增、修改

	新增:
        1. 前端传入后端的数据,不论编码格式,都在request.data中,request.data格式是字典
		   前端根据传入的编码格式不一样,从request.data取到的字典形式也是不一样的
		      编码格式                   字典
             urlencoded               QueryDict
              form-data                QueryDict
               json                       dict
        2. 将前端传入的数据request.data进行反序列化,并完成序列化类的反序列化
        3. 序列化类得到对象并传入参数:data=request.data
               校验数据
               保存:ser.save()--->序列化类中重写create方法
    
    修改:
        1. 拿到前端传入的数据,进行反序列化,查出要修改的对象--->序列化类的反序列化
        2. 序列化类得到对象,传入参数:instance=要修改的对象,data=request.data
               校验数据 
               保存:ser.save()  --->序列化类中重写update方法

反序列化的新增

序列化类

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

视图类

	class BookView(APIView):
	    def get(self, request):  # 获取多条数据
	        book_list = models.Book.objects.all()
	        '''instance表示要序列化的数据,many=True表示序列化多条(instance是QuerySet对象)'''
	        ser = BookSerializer(instance=book_list, many=True)  # 序列化多条需要many=True
	        return Response({
   
   'code': 100, 'msg': '查询成功', 'results': ser.data})
	
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值