首页 > 其他分享 >drf学习笔记

drf学习笔记

时间:2022-09-27 18:23:29浏览次数:52  
标签:serializers name self publish 学习 length 笔记 序列化 drf

今日内容概要

  • 序列化类常用字段类和字段参数
  • 序列化类高级用法之source
  • 序列化类高级用法之定制序列化字段的两种方式
  • 反序列化之数据校验
  • 模型类序列化器的使用
  • 反序列化数据校验源码分析
  • 断言assert

今日内容详细

序列化类常用字段和字段参数

字段类

### 字段类:跟models一一对应,但是比它多
# BooleanField
# NullBooleanField
# CharField
# EmailField
# RegexField
# SlugField
# URLField
# UUIDField
# IPAddressField
# IntegerField
# FloatField
# DecimalField
# DateTimeField
# DateField
# TimeField
# ChoiceField
# FileField
# ImageField

---------记住一下几个-----------
CharField
BooleanField
IntegerField
DecimalField


------ 以上都是models有的----下面是serializer独有的---
ListField
DictField

字段参数

# 选项参数:
参数名称                  作用
# 给CharField字段类使用的参数
max_length             最大长度
min_lenght             最小长度
allow_blank            是否允许为空
trim_whitespace        是否截断空白字符


# 给IntegerField字段类使用的参数
max_value              最小值
min_value              最大值


# 通用参数:放在哪个字段类上都可以的
required            表明该字段在反序列化时必须输入,默认True
default             反序列化时使用的默认值
allow_null          表明该字段是否允许传入None,默认False
validators          该字段使用的验证器【不需要了解】
error_messages      包含错误编号与错误信息的字典
label               用于HTML展示API页面时,显示的字段名称
help_text           用于HTML展示API页面时,显示的字段帮助提示信息


# 重点
read_only          表明该字段仅用于序列化输出,默认False
write_only         表明该字段仅用于反序列化输入,默认False

序列化类高级用法之source

可以修改序列化字段的名字
book_name = serializers.CharField(max_length=8, min_length=3, source='name')

1.使用source等于字段参数,可以指定序列化表中得哪个字段
2.source指定的可以是字段,也可以是方法,用于重命名
3.source可以做跨表查询

代码演示

class BookSerializer(serializers.Serializer):
    name_detail = serializers.CharField(max_length=8, min_length=3,source='name')
    # 或
    publish_name = serializers.CharField(max_length=8,
                                         min_length=3,source='publish.name')
    # 或
    xx = serializers.CharField(max_length=8, min_length=3,source='xx') #source的xx表示表模型中得方法

序列化类高级用法之定制序列化字段的两种方式

方式一:在序列化类中使用SerializerMethodField

class BookSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=8, min_length=3)
    price = serializers.IntegerField(min_value=10, max_value=99)
    publish_date = serializers.DateField()
    # publish要序列化成 {name:北京出版社,city:北京,email:[email protected]}
    # SerializerMethodField必须配合一个方法(get_字段名,需要接受一个参数),方法返回什么,这个字段就是什么
    publish = serializers.SerializerMethodField()
    def get_publish(self, obj):
        # obj 是当前序列化的对象
        return {'name': obj.publish.name, 'city': obj.publish.city, 'email': obj.publish.email}

    # 用方式一,显示所有作者对象  []
    authors = serializers.SerializerMethodField()
    def get_authors(self, obj):
        res_list = []
        for author in obj.authors.all():
            res_list.append({'id': author.id, 'name': author.name, 'age': author.age})
        return res_list

方式二:在表模型中写方法

# 表模型中
class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish_date = models.DateField(null=True)

    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    authors = models.ManyToManyField(to='Author')

    # 写了个方法,可以包装成数据属性,也可以不包
    # @property
    def publish_detail(self):
        return {'name': self.publish.name, 'city': self.publish.city, 'email': self.publish.email}

    def author_list(self):
        res_list = []
        for author in self.authors.all():
            res_list.append({'id': author.id, 'name': author.name, 'age': author.age})
        return res_list

    # 在模型类中写逻辑代码,称之为ddd,领域驱动模型
# 序列化类中
class BookSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=8, min_length=3)
    price = serializers.IntegerField(min_value=10, max_value=99)
    publish_date = serializers.DateField()

    # 在表模型中写方法
    publish_detail = serializers.DictField(read_only=True)
    # 使用方式二实现,显示所有作者
    author_list = serializers.ListField(read_only=True)

有关联关系表的反序列化的保存

1. 序列化字段和反序列化字段不一样  【序列化类中】
    # 反序列化用的
    publish = serializers.CharField(write_only=True)
    authors = serializers.ListField(write_only=True)
    #序列化用的
    publish_detail = serializers.DictField(read_only=True)
    author_list = serializers.ListField(read_only=True)

2. 一定要重写create  【序列化类中】
def create(self, validated_data): 
    # validated_data 校验过后的数据  
    {"name":"三国1演义",
     "price":19,
     "publish_date": "2022-09-27",
     "publish":1,
     "authors":[1,2]
    }
    book = Book.objects.create(name=validated_data.get('name'),
                               price=validated_data.get('price'),
                               publish_date=validated_data.get('publish_date'),
                               publish_id=validated_data.get('publish'),
                               authors_id= validated_data.getlist('authors'),
                              )
    authors = validated_data.get('authors')
    book.authors.add(*authors)
    return book

使用继承Serializer的序列化类保存的缺点

1.在序列化中每个字段都要写,无论是序列化还是反序列化

2.如果新增或修改,在序列化类中都需要重写create或update

反序列化之数据校验

无论新增还是修改,只要执行ser.is_valid()就会触发校验。

跟forms很像:先走字段自己的校验规则,再走局部钩子,再走全局钩子。

字段自己的校验规则

-如果继承的是Serializer,写法如下
    name=serializers.CharField(max_length=8,min_length=3,error_messages={
        'min_length': "太短了"
    })
-如果继承的是ModelSerializer,写法如下
    extra_kwargs = {
            'name': {'max_length': 8, 'min_length': 3, 'error_messages': { 
                'min_length': "太短了"}
                    },
    }

局部钩子

-如果继承的是Serializer,写法一样
-如果继承的是ModelSerializer,写法一样
def validate_name(self, name):
    # name就是  要校验的字段对应的前端传入的值
    if name.startswith('sb'):
        # 校验不通过,抛异常
        raise ValidationError('不能以sb卡头')
    else:
        # 需要返回字段
        return name

全局钩子

-如果继承的是Serializer,写法一样
-如果继承的是ModelSerializer,写法一样
def validate(self, attrs):
    # attrs 校验过后的数据,字段自己校验完后就是局部钩子走完过的数据
    if attrs.get('name') == attrs.get('publish_date'):
        raise ValidationError('名字不能等于日期')
    else:
        return attrs

模型类序列化器的使用

#  如何使用
1 定义一个类继承ModelSerializer
2 类内部写内部内 class Meta:
3 在内部类中指定model(要序列化的表)
4 在内部类中指定fields(要序列化的字段,写__all__表示所有,不包含方法,还可以写[一个个字段])
5 在内部类中指定extra_kwargs,给字段添加字段参数的
6 在序列化类中,可以重写某个字段,优先使用你重写的
    name = serializers.SerializerMethodField()
    def get_name(self, obj):
        return 'sb---' + obj.name
7 以后不需要重写create和update了
    ModelSerializer写好了,兼容性更好,任意表都可以直接存

代码演示

class BookModelSerializer(serializers.ModelSerializer):
    # 不需要写字段了,字段从表模型映射过来
    class Meta:
        model = Book  # 要序列化的表模型
        fields = ['name', 'price', 'publish_date', 'publish', 'authors', 'publish_de', 'author_li']  # 列表中有什么,就是序列化哪个字段
        # 给authors和publish加write_only属性
        # name加max_len属性
        extra_kwargs = {
            'name': {'max_length': 8},
            'publish': {'write_only': True},
            'authors': {'write_only': True},

    publish_detail = serializers.SerializerMethodField(read_only=True)
    def get_publish_detail(self, obj):
        # obj 是当前序列化的对象
        return {'name': obj.publish.name, 'city': obj.publish.city, 'email': obj.publish.email}

    author_list = serializers.SerializerMethodField(read_only=True)
    def get_author_list(self, obj):
        res_list = []
        for author in obj.authors.all():
            res_list.append({'id': author.id, 'name': author.name, 'age': author.age})
        return res_list

反序列化数据校验源码分析

# 先校验字段自己的规则(最大,最小),走局部钩子校验,走全局钩子
# 局部:validate_name,全局叫:validate 为什么?

你自己写的序列化类---》继承了ModelSerializer---》继承了Serializer---》BaseSerializer---》Field

1.从哪开始看?哪个操作执行了字段校验(ser.is_valid())
# BaseSerializer内的is_valid()方法
def is_valid(self, *, raise_exception=False):
    if not hasattr(self, '_validated_data'):
        try:
            # 真正的走校验,如果成功,返回校验过后的数据
            self._validated_data = self.run_validation(self.initial_data)
        except ValidationError as exc:
    return not bool(self._errors)
2.内部执行了:self.run_validation(self.initial_data)---》本质执行的Serializer类里的
# 如果你按住ctrl键,鼠标点击,会从当前类中找run_validation,找不到会去父类找
# 代码执行每次都要从头开始找,从自己身上再往上找
def run_validation(self, data=empty):
    #局部钩子的执行
    value = self.to_internal_value(data)
    try:
        # 全局钩子的执行,从根上开始找着执行,优先执行自己定义的序列化类中得全局钩子
        value = self.validate(value)
    except (ValidationError, DjangoValidationError) as exc:
        raise ValidationError(detail=as_serializer_error(exc))
    return value
3.全局钩子看完了,局部钩子---》 self.to_internal_value---》从根上找----》本质执行的Serializer的
def to_internal_value(self, data):
    for field in fields: # fields:序列化类中所有的字段,for循环每次取一个字段对象
        # 反射:去self:序列化类的对象中,反射 validate_字段名 的方法
        validate_method = getattr(self, 'validate_' + field.field_name, None)
        try:
            # 这句话是字段自己的校验规则(最大最小长度)
            validated_value = field.run_validation(primitive_value)
            # 局部钩子
            if validate_method is not None:
                validated_value = validate_method(validated_value)
        except ValidationError as exc:
            errors[field.field_name] = exc.detail
    return ret

断言assert

# 框架的源码中,大量使用断言
assert :断言,作用的判断,断定一个变量必须是xx,如果不是就报错

# 你的土鳖写法
# name = 'lqz1'
# if not name == 'lqz':
#     raise Exception('name不等于lqz')
# print('程序执行完了')

# assert的断言写法
name = 'lqz1'
assert name == 'lqz', 'name不等于lqz'
print('程序执行完了')

标签:serializers,name,self,publish,学习,length,笔记,序列化,drf
From: https://www.cnblogs.com/wwjjll/p/16735496.html

相关文章

  • Python学习:绑定方法与非绑定方法
    一、绑定方法与非绑定方法类中定义的函数分为两大类:绑定方法和非绑定方法其中绑定方法又分为绑定到对象的对象方法和绑定到类的类方法。在类中正常定义的函数默认是绑定......
  • 快学 VisionPro 系列教程 笔记
    视频来源:b站https://www.bilibili.com/video/BV1ZS4y197mk/?spm_id_from=333.337.search-card.all.click&vd_source=ed0219dc0ed7a6e1d0ced6918306b5b5   VisionPr......
  • 关于DNS服务器无域名主机配置的笔记
    centos下配置named的DNS服务器,首先按一般流程配置(略)当需要配置只有主机名,没有域名的情况时,主要是两点:1、在/etc/named.rfc1912.zones里面添加:zone"."IN{ty......
  • 2022-2023-1 20211326《信息安全专业导论》第五周学习总结
    作业信息信息安全专业导论第四周作业:|无穷的技艺作业||我的黑客偶像|正文链接:https://www.cnblogs.com/TonySSS/教材学习内容总结|看漫画学Python第五章|学习了分支......
  • Flask 学习-79.Flask-RESTX 参数校验reqparse 解析器继承与更新
    前言通常我们会为每个资源创建不同的解析器,如果多个解析器直接有共同的参数,可以写一个包含所有共享参数的父解析器。然后使用copy()复制一个父类解析器同一个参数覆盖......
  • 【C++】之前学习C++没有注意到的点或者学到了冷知识(待补充)
    1.string和c_str()stringstr="hello";constchar*cstr=str.c_str();str="yep,im";本来是以为str.c_str()会把str中包含的字符串在内存中开辟一个新空间存放......
  • 5个cpp学习网站
    5个学习cpp的网站相对其他语言来说,C++算是难度比较高的了,这一点无法否认。但是如果能有一些好的网站,则会让C++的学习事半功倍。那就来介绍几个最常用的(最好的)吧,包含了......
  • java怎么入门,哪些经验是值得学习的
    新手学JAVA怎么入门?下面有一些建议和学习方法,希望能够对想学JAVA的人有所帮助!1.确立明确的学习目标首先你要弄清楚自己学JAVA的目的是什么,是仅仅出于兴趣想了解一下这门......
  • PCIE背景知识学习(6)
    PCIE背景知识学习(6)物理层物理层的LTSSM(LinkTrainingandStatusStateMachine,链路训练状态机)负责进行链路初始化以及训练。 为了更容易看出这个数据包是怎么构成的,......
  • PCIE背景知识学习(7)
    PCIE背景知识学习(7)每个PCIe功能(Function)的标识在其所在的设备内,以及这个设备所连接的总线内,都是唯一的。其标识符一般被称为“BDF”。   仔细看图中的总线序号,观察......