序列化类常用字段类和字段参数,序列化类高级用法之source,修改序列化字段名字,定制序列化字段的两种方式, 反序列化之数据校验,模型类序列化器(ModelSerializer)的使用,反序列化数据校验源码分析(了解),断言assert

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(maxlength=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' 
# 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)
*******************************************************以下需要记住并熟练使用**********************************************************************************
CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
BooleanField    BooleanField()
IntegerField    IntegerField(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: 小数点位置

列表:Listfield :{name:'沸羊羊',age:19,hobby:['健身','美羊羊']}

字典:Dictfield :{name:'沸羊羊',age:19,nowife:{'name':'美羊羊','age':15}}

 
复制代码

2.序列化类高级用法

(1)source,修改序列化字段的名字

source可以使返回前端的字段名随意变化,只要在返回前端的字段名中加属性source,使source = ‘字段名’,但是使用source不能使字段名等于前端返回的字段名(就是不能多次一举,闲的没事干),course还可以做跨表查询

想要在前端显示的名字 = serializers.CharField(max_length=32,source='表中字段名')
跨表查询,需要连表
在前端显示的名字 = serializers.CharField(max_length=32,source='表名.前面表名中的字段名')

(2)定制序列化字段的两种方式

  方式一

复制代码
在序列化中用SerializerMethodField(千万别手快点成ModelSerializer)
serializers.py中的类中加入
publish = serializers.SerializerMethodField()
def get_publish(self,obj):
return {'name':obj.publish.name,'city':obj.publish.city,'email':obj.publish.email}

如果数据有多条,例如publish.name 有两个就需要使用for循环把他们一个一个取出来在放进一个列表中最后返回
def get_authors(self, obj):
list_authors = []
for author in obj.authors.all():
list_authors.append({'id': author.id, 'name': author.name, 'age': author.age})
return list_authors

复制代码

    方式二

复制代码
在models中插入
def get_publish(self):
  return{'name':self.publish.name,'city':self.publish.city,'email':self.publish.email}

然后在serializers.py类中要加入
get_publish =serializers.DictField()

同上只不过代码换个位置在在serializers中调用

复制代码

  read.only与wirte.only

read.only = Ture
read.only是只在返回给前端数据时才会显示
write.only = Ture
write.only是前端给后端数据是才会显示

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

复制代码
    publish = serializers.IntegerField(write_only=True)
    # publish = serializers.CharField()
    # authors = serializers.ListField(write_only=True)
    authors = serializers.ListField(write_only=True)


    publish_date = serializers.DateField()
    publish_detail = serializers.DictField(read_only=True)
    get_authors = serializers.ListField(read_only=True)
复制代码

上述代码中如果遇到IntegerField和ListField必须要加(write_only=True)不然数据可以存到数据库,但是返回前端的数据会报错显示不出来。同时要从写create,不然也会报错

复制代码
 def create(self, validated_data):
        res = 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 = validated_data.get('authors')
        res.authors.add(*authors)
        # del validated_data['Publish']  这是我调试上面问题写的,暂且忽略
        return res
复制代码

 

3.反序列化之数据校验

数据校验规则跟froms很像,都是先校验自己制定的规则,然后校验局部钩子,最后校验全局钩子

复制代码
# 这是自己写的规则
    name = serializers.CharField(label='书名',required=True,error_messages={
        'required': '书名不能不填'})
    price = serializers.DecimalField(label='价格',required=True,max_digits=7, decimal_places=2,error_messages={
        'max_digits':'书太贵了你是来坑钱的吗',
        'required': '你这书真的要白送吗'})
    publish = serializers.CharField(max_length=8, min_length=3, label='出版社名字', required=True, error_messages={
        'max_length': '出版社名字太长了装不下啦',
        'min_length': '你这出版社盗版的嘛,名字那么短',
        'required': '这个必填'
    })
复制代码
复制代码
# 局部钩子
def validate_name(self, name):
if 'sb' in name:
raise ValidationError('名称中不能有sb')
return name

def validate_price(self, price):
if price == 66:
raise ValidationError('价格不能为66')
return price
复制代码
复制代码
# 全局钩子
全局钩子在碰到两次密码校验时会用
def clean(self):
  password=self.cleaned_data.get('password')
  re_password=self.cleaned_data.get('re_password')
  if re_password==password: #校验通过
    return self.cleaned_data
  else:
    raise ValidationError('两次密码不一致')

 
复制代码

4.模型类序列化器(ModelSerializer)的使用

与Serializer基本一致,不需要重写create和update方法,就是后面要加Mate,不然会报错,Meta中model要等于序列化表的模型,fields是序列化字段名

复制代码
class BookSerializer(serializers.ModelSerializer):
name = serializers.CharField(label='书名', max_length=8, min_length=3, error_messages={
'required': '书名不能不填'})
price = serializers.DecimalField(label='价格', required=True, max_value=199, min_value=9, max_digits=7,
decimal_places=2, error_messages={
'max_digits': '书太贵了你是来坑钱的吗',
'required': '你这书真的要白送吗'})
# publish = serializers.IntegerField(write_only=True)
# publish = serializers.CharField(write_only=True)
# authors = serializers.ListField(write_only=True)
authors = serializers.ListField(write_only=True)

publish_date = serializers.DateField()
publish_detail = serializers.DictField(read_only=True)
get_authors = serializers.ListField(read_only=True)

extra_kwargs = {'name': {'max_length': 6},
'publish':{'write_only':True}}

class Meta:
model = Book
fields = ['name', 'price', 'publish', 'authors', 'publish_date', 'publish_detail', 'get_authors']

def validate_name(self, name):
if 'sb' in name:
raise ValidationError('名称中不能有sb')
return name

def validate_price(self, price):
if price == 66:
raise ValidationError('价格不能为66')
return price
复制代码

extra_kwargs

在ModelSerializer中会有一个extra_kwargs,可以给别的字段名加参数

例:
extra_kwargs = {'name':{max_length=6}

 

5.反序列化数据校验源码分析(了解)

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

# 入口:从哪开始看,哪个操作,执行了字段校验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)
    
    -内部执行了: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
  -全局钩子看完了,局部钩子---》 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
    
 # 你自己写的序列化类---》继承了ModelSerializer---》继承了Serializer---》BaseSerializer---》Field
复制代码

6.断言assert

复制代码
常规的土鳖写法
list = 'bxf'
if  'b' in list:
    print('')
print('没有')
print('完了')


装逼的断言写法

list = 'bxf'
assert 'b' in list, '没有'
print'完了'
复制代码

 

posted @   shangxin_bai  阅读(138)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示