DRF ~ day03 之新的request源码分析、序列化组件介绍、序列化类,序列化器和单个对象,常用字段类型和字段参数、反序列化的校验、反序列化的之保存

DRF之新的request源码分析、序列化组件介绍、序列化类,序列化器和单个对象,常用字段类型和字段参数、反序列化的校验、反序列化的之保存



一、新的request源码分析

# 源码中找出来,从Request查找
from rest_framework.request import Request

# 进入到Request模块中
class Request:
	# Request的方法里面的request就是老的request,它是之前从APIView里面的dispatch里面的request传过来的
	'''
	def dispatch(self, request, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs
        # 这下面一行代码就是APIView里面的dispatch把老的request传递给新的request
        # request新的(rest_framework.request.Request) =  request老的(django.core.handlers.wsgi.WSGIRequest)
        request = self.initialize_request(request, *args, **kwargs)
	'''
    def __init__(self, request, parsers=None, authenticators=None,
                 negotiator=None, parser_context=None):
        assert isinstance(request, HttpRequest), (
            'The `request` argument must be an instance of '
            '`django.http.HttpRequest`, not `{}.{}`.'
            .format(request.__class__.__module__, request.__class__.__name__)
        )
		# 这里就是把之前的老的赋值给新的_request 
        self._request = request
        self.parsers = parsers or ()
        self.authenticators = authenticators or ()
        self.negotiator = negotiator or self._default_negotiator()
        self.parser_context = parser_context
        self._data = Empty
        self._files = Empty
        self._full_data = Empty
        self._content_type = Empty
        self._stream = Empty

# 由上面可知在Request模块中,一定由方法实现request新老交互的功能
    def __getattr__(self, attr):
        """
        If an attribute does not exist on this instance, then we also attempt
        to proxy it to the underlying HttpRequest object.
        """
        try:
        	# 新的_request重写了__getattr__,通过反射获取老的request中的属性
            return getattr(self._request, attr)
        except AttributeError:
            return self.__getattribute__(attr)

# APIView+Response写个接口
# 视图层里面的代码
import json

from django.shortcuts import render
from django.http import JsonResponse

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request


class BookView(APIView):
    def get(self, request):
        # # print(request.POST)
        # print(request.GET)
        # print('---',request.query_params)
        # print(request.data)
        print(type(request._request))
        print(request._request.GET)
        return Response('ook')

    def post(self, request):
        # request是新的
        print(type(request))  # rest_framework.request.Request
        # 以后,无论post还是put请求放在body体中的数据,无论那种编码格式,都是从request.data中取
        # print(request.data)  # 原来的的request没有data属性,新的有了

        # 原来的request.POST 还有
        # print(request.POST)

        # 提交文件form-data格式,还在 request.FILES中
        # print(request.FILES)

        # 其他的所有属性,都跟之前一模一样
        print(request.method)
        print(request.body)
        print(request.path)

        return Response('ok')  # Response跟JsonResponse很像,可以传字符串,列表,字典都可以,就是不能传对象


# 总结:
	1 新的request有个data属性,以后只要是在请求body体中的数据,无论什么编码格式,无论什么请求方式
    2 取文件还是从:request.FILES
    3 取其他属性,跟之前完全一样 request.method  ....
    	-原理是:新的Request重写了__getattr__,通过反射获取老的request中的属性
    4 request.GET 现在可以使用 request.query_params
    	   @property
            def query_params(self):
                return self._request.GET
    
    
    
# 源码中找出来 
	-老的request在新的request._request
    -照常理来讲,如果取method,应该request._request.method,但是我现在可以request.method
    
   
    
    
# 魔法方法之 __getattr__, . 拦截,对象.属性 当属性不存在时,会触发 类中 __getattr__的执行
# get请求能不能在body体中带数据
	--以后只要继承了APIView及其子类,视图类中的方法中的request已经不是原来的request了
-request.data    无论任何请求,body体中携带的数据,到了后端,全都放到它中,是个字典
-前端传入的文件,request.FILES中取
-get请求提交的数据【在请求地址中的数据】---》后端request.GET-->request.query_params
-method,path,之前用过的,都是从  request.取得值即可

-魔法方法   __getattr__   . 拦截   对象.属性   如果对象中不存在这个属性,就会触发__getattr__的执行,__getattr__返回什么,就拿到什么

request.path发__getattr__(self, attr) ---->attr='path'  request中根据字符串取出'path'


二、序列化组件介绍

2.1、 序列化器-Serializer

Serializer的作用:

  1. 序列化,序列化器会把模型对象(queryset,单个对象)转换成字典,经过response以后变成json字符串
  2. 反序列化,把客户端发送过来的数据,经过request.data以后变成字典,序列化器可以把字典转成模型
  3. 反序列化,完成数据校验功能

2.2、 定义序列化器

Django REST framework中的Serializer使用类来定义,须继承自rest_framework.serializers.Serializer。

1、例如,我们已有了一个数据库模型类Book (在models.py文件中创建表)

from django.db import models


class Book(models.Model):
    name = models.CharField(max_length=64)
    price = models.IntegerField()

2、我们想为这个模型类提供一个序列化器,可以定义如下:创建序列化器Serializer (这里的意思是创建一个Serializer.py的文件夹用来创建序列化类)

# 新建一个序列化器
from rest_framework import serializers
# 声明序列化器,所有的序列化器都要直接或者间接继承于 Serializer
# 其中,ModelSerializer是Serializer的子类,ModelSerializer在Serializer的基础上进行了代码简化
from rest_framework.exceptions import ValidationError
from .models import Book


class Bookserializers(serializers.Serializer):
    # 1. 需要进行数据转换的字段( 要序列化的字段 )
from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    # 要序列化的字段
    id = serializers.IntegerField()
    name = serializers.CharField()
    price = serializers.IntegerField()
    # 2. 如果序列化器集成的是ModelSerializer,则需要声明调用的模型信息
		。。。
    # 3. 验证代码
		。。。
    # 4. 编写添加和更新模型的代码
    	。。。

注意:serializer不是只能为数据库模型类定义,也可以为非数据库模型类的数据定义。serializer是独立于数据库之外的存在。

三、 序列化类的基本使用(基于APIView+序列化类+Response实现book表的查询所有or单个的接口功能,)

3.1、创建单表模型(即orm单表查询出来的对象)

from django.db import models


class Book(models.Model):
    name = models.CharField(max_length=64)
    price = models.IntegerField()

3.2、创建序列化类(创建一个Serializer.py的文件夹,用来完成数据的序列化)

使用序列化类,完成序列化 两个很重要参数: instance实例,对象 data:数据

from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    # 要序列化的字段
    id = serializers.IntegerField()
    name = serializers.CharField()
    price = serializers.IntegerField()

3.3、设置路由

from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    # 开始接口
    path('bookint/', views.Bookint.as_view()),
    path('book/<int:pk>/', views.Bookintdan.as_view()),

]

3.4、视图类的代码

import json

from django.shortcuts import render
from django.http import JsonResponse

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
#导入表模型
from .models import Book
# 导入序列化类
from .serializer import BookSerializer


class BookView(APIView):
    def get(self, request):
        book_list = Book.objects.all()
        # 使用序列化类,完成序列化  两个很重要参数: instance实例,对象      data:数据
        # 如果是多条many=True  如果是queryset对象,就要写
        # 如果是单个对象 many=False,默认是False
        serializer = BookSerializer(instance=book_list, many=True)
        # serializer.data  # 把qs对象,转成列表套字典  ReturnList
        # print(serializer.data)
        # print(type(serializer.data))
        # return Response(serializer.data)
        return Response({'code': 100, 'msg': '成功', 'data': serializer.data})


class BookDetailView(APIView):
    def get(self, request, pk):
        book = Book.objects.all().get(pk=pk)
        serializer = BookSerializer(instance=book)
        return Response({'code': 100, 'msg': '成功', 'data': serializer.data})

3.5、postman展示

postman查询一条
在这里插入图片描述
查询所有
在这里插入图片描述

3.6、总结

# 序列化类的使用
1 写一个类,继承serializers.Serializer
2 在类中写字段,要序列化的字段
3 在视图类中使用:(多条,单条)
    serializer = BookSerializer(instance=book_list, many=True)
    serializer = BookSerializer(instance=book)

四、常用字段类型

常用字段类型:


### 4.1 常用字段类

| **BooleanField**        | BooleanField()                                               |
| ----------------------- | ------------------------------------------------------------ |
| **NullBooleanField**    | NullBooleanField()                                           |
| **CharField**           | CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) |
| 字段                    | 字段构造方式                                                 |
| **EmailField**          | EmailField(max_length=None, min_length=None, allow_blank=False) |
| **RegexField**          | RegexField(regex, max_length=None, min_length=None, allow_blank=False) |
| **SlugField**           | SlugField(max*length=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9*-]+ |
| **URLField**            | URLField(max_length=200, min_length=None, allow_blank=False) |
| **UUIDField**           | UUIDField(format=’hex_verbose’) format: 1) `'hex_verbose'` 如`"5ce0e9a5-5ffa-654b-cee0-1238041fb31a"` 2) `'hex'` 如 `"5ce0e9a55ffa654bcee01238041fb31a"` 3)`'int'` -: `"123456789012312313134124512351145145114"` 4)`'urn'` 如: `"urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"` |
| **IPAddressField**      | IPAddressField(protocol=’both’, unpack_ipv4=False, **options) |
| **IntegerField**        | IntegerField(max_value=None, min_value=None)                 |
| **FloatField**          | FloatField(max_value=None, min_value=None)                   |
| **DecimalField**        | DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置 |
| **DateTimeField**       | DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) |
| **DateField**           | DateField(format=api_settings.DATE_FORMAT, input_formats=None) |
| **TimeField**           | TimeField(format=api_settings.TIME_FORMAT, input_formats=None) |
| **DurationField**       | DurationField()                                              |
| **ChoiceField**         | ChoiceField(choices) choices与Django的用法相同               |
| **MultipleChoiceField** | MultipleChoiceField(choices)                                 |
| **FileField**           | FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
| **ImageField**          | ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
| **ListField**           | ListField(child=, min_length=None, max_length=None)          |
| **DictField**           | DictField(child=)                                            |

五、字段参数

'''
选项参数:

参数名称	作用
max_length	最大长度
min_lenght	最小长度
allow_blank	是否允许为空
trim_whitespace	是否截断空白字符
max_value	最小值
min_value	最大值
通用参数:

参数名称	说明
read_only	表明该字段仅用于序列化输出,默认False
write_only	表明该字段仅用于反序列化输入,默认False
required	表明该字段在反序列化时必须输入,默认True
default	反序列化时使用的默认值
allow_null	表明该字段是否允许传入None,默认False
validators	该字段使用的验证器
error_messages	包含错误编号与错误信息的字典
label	用于HTML展示API页面时,显示的字段名称
help_text	用于HTML展示API页面时,显示的字段帮助提示信息
'''

六、反序列化的校验

# 反序列化,有三层校验
    -1 字段自己的(写的字段参数:required   max_length 。。。)
    -2 局部钩子:写在序列化类中的方法,方法名必须是 validate_字段名
    	def validate_name(self, name):
            if 'sb' in name:
                # 不合法,抛异常
                raise ValidationError('书名中不能包含sb')
            else:
                return name
    -3 全局钩子:写在序列化类中的方法 方法名必须是 validate
       def validate(self, attrs):
            price = attrs.get('price')
            name = attrs.get('name')
            if name == price:
                raise ValidationError('价格不能等于书名')
            else:
                return attrs
            
  # 只有三层都通过,在视图类中:
	ser.is_valid():  才是True,才能保存

七、反序列化的之保存

# 新增接口:
	-序列化类的对象,实例化的时候:ser = BookSerializer(data=request.data)
	-数据校验过后----》调用  序列化类.save()--->但是要在序列化类中重写  create方法
        def create(self, validated_data):
            book=Book.objects.create(**validated_data)
            return book
        
        
# 修改接口
	-序列化类的对象,实例化的时候:ser = BookSerializer(instance=book,data=request.data)
	-数据校验过后----》调用  序列化类.save()--->但是要在序列化类中重写  update方法
        def update(self, book, validated_data):
            for item in validated_data:  # {"name":"jinping","price":55}
                setattr(book, item, validated_data[item])
            book.save()
            return book
        
        
# 研究了一个问题
	在视图类中,无论是保存还是修改,都是调用序列化类.save(),底层实现是根据instance做一个判断

八、代码展示

8.1、视图层代码

from rest_framework.views import APIView
from app01 import models
from rest_framework.response import Response

from .serializer import Bookserializers


class Bookint(APIView):
    # 查询所有数据
    def get(self, request):
        books_obj = models.Book.objects.all()
        # print(books_obj)  # QuerySet 的对象
        # 使用序列化类,完成序列化  两个很重要参数: instance实例,对象      data:数据
        # 如果是多条many=True  如果是queryset对象,就要写
        # 如果是单个对象 many=False,默认是False
        res = Bookserializers(instance=books_obj, many=True)  # 使用序列化器序列化数据
        print(res.data)  # 得到的是OrderedDict 把 QuerySet对象,转成列表套字典  ReturnList
        print(type(res.data))  # <class 'rest_framework.utils.serializer_helpers.ReturnList'>
        return Response({"code": 200, 'msg': '成功', 'data': res.data})

    # 新增数据
    def post(self, request):
        # 前端会传入数据,request.data--->把这个数据保存到数据库中
        # 借助于序列化类,完成 校验和反序列化
        # data 前端传入的数据 {"name":"三国演义","price":88}
        print(request.data)
        # 接收前端数据进行反序列化
        ser = Bookserializers(data=request.data)  # 反序列化前端的数据
        # data=request.data 是把数据传入序列化器中进行数据处理

        # 校验数据
        if ser.is_valid():  # 三层:字段自己的校验,局部钩子校验,全局钩子校验  写在
            print(ser.validated_data)  # validated_data:校验过后的数据
            # 校验之后要保存数据
            # 如果没有save,如何保存,自己做
            # Book.objects.create(**ser.validated_data)
            ser.save()   # 会保存,但是会报错,因为它不知道你要保存到那个表中
            return Response({"code": 200, 'msg': '新增成功'})
        else:
            print(ser.errors)  # 校验失败的错误
            return Response({"code": 200, 'msg': '新增失败', 'data': ser.errors})


class Bookintdan(APIView):
    def get(self, request, pk):
        res_obj = models.Book.objects.all().get(pk=pk)
        print(res_obj)
        res = Bookserializers(instance=res_obj, many=False)  # 序列化 单条数据是many可以不写
        print(res.data)
        return Response({"code": 200, 'msg': '成功', 'data': res.data})

    # 修改一条数据
    def put(self, request, pk):
        book = models.Book.objects.get(pk=pk)
        ser = Bookserializers(instance=book, data=request.data)
        if ser.is_valid():
            ser.save()  # 也会报错,重写update
            return Response({"code": 200, 'msg': '修改成功'})
        else:
            return Response({"code": 200, 'msg': '修改失败', 'data': ser.errors})
    
    # 删除一条数据
    def delete(self, request, pk):
        models.Book.objects.filter(pk=pk).first().delete()
        return Response({"code": 200, 'msg': '删除成功'})

8.2、路由层代码

from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
    path('admin/', admin.site.urls),
    # 开始接口
    path('bookint/', views.Bookint.as_view()),
    path('book/<int:pk>/', views.Bookintdan.as_view()),

]

8.3、序列化器的代码

# 新建一个序列化器
from rest_framework import serializers
# 声明序列化器,所有的序列化器都要直接或者间接继承于 Serializer
# 其中,ModelSerializer是Serializer的子类,ModelSerializer在Serializer的基础上进行了代码简化
from rest_framework.exceptions import ValidationError
from .models import Book


class Bookserializers(serializers.Serializer):
    # 1. 需要进行数据转换的字段( 要序列化的字段 )
    id = serializers.IntegerField(required=False)  # 前端传入数据,可以不填这个字段
    name = serializers.CharField(allow_blank=True, required=False, max_length=8,
                                 min_length=3, error_messages={'max_length': '数据太长了'}
                                 )  # # allow_blank: 这个字段传了,value值可以为空
    peice = serializers.IntegerField()

    # 局部钩子:给某个字段做个校验
    #     # 书名中不能包含sb
    #     # validate_字段名
    def validate_name(self, name):
        if 'sb' in name:
            raise ValidationError('书名中不能包含sb‘')
        else:
            return name

    def validate_price(self, item):
        if item == 88:
            raise ValidationError('价格不能等于88')
        else:
            return item

    # 全局钩子
    def validate(self, attrs):
        name = attrs.get('name')
        price = attrs.get('price')
        if name == price:
            raise ValidationError('价格不能等于书名')
        else:
            return attrs

    def create(self, validated_data):
        # 通过 validated_data 三层校验之后的数据是字典
        # 把字典打撒传到validated_data中
        # validated_data 数据是前端传来的
        book = Book.objects.create(**validated_data)
        return book

    def update(self, instance, validated_data):
        # instance 要修改的对象 接收前端的book
        # validated_data:前端传入,并且校验过后的数据 接收前端的request.data
        instance.name = validated_data.get('name')
        instance.price = validated_data.get("price")
        instance.save()
        '''
        for item in validated_data:
             setattr(book, item, validated_data[item])
        instance.save()
        
        # 等同于下面
        #   setattr(book,'name','jinping')
        #   setattr(book,'price',55)
        # 等同于
        #     book.name = validated_data.get('name')
        #     book.price = validated_data.get('price')
        '''
        return instance



8.4、模型层代码

from django.db import models


class Book(models.Model):
    name = models.CharField(max_length=64)
    peice = models.IntegerField()

8.5、postman展示

数据库的数据展示
在这里插入图片描述

postnam操作:

新增一条数据
在这里插入图片描述

修改一条数据
在这里插入图片描述

删除一条数据
在这里插入图片描述


总结

以上就是今天要讲的内容,本文仅仅简单介绍了 序列化和反序列化 的使用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值