DRF中的序列化与反序列化

Serializer字段与选项大全

常用字段类型

字段字段构造方式
BooleanFieldBooleanField()
NullBooleanFieldNullBooleanField()
CharFieldCharField(max_length=None, min_length=None, allow_blank=False,
EmailFieldEmailField(max_length=None, min_length=None, allow_blank=False)
RegexFieldRegexField(regex, max_length=None, min_length=None, allow_blank=False)
SlugFieldSlugField(max_length=50, min_length=None, allow_blank=False) 正则字段,验证正则模式
URLFieldURLField(max_length=200, min_length=None, allow_blank=False)
UUIDFieldUUIDField(format=‘hex_verbose’)
IPAddressFieldIPAddressField(protocol=‘both’, unpack_ipv4=False, **options)
IntegerFieldIntegerField(max_value=None, min_value=None)
FloatFieldFloatField(max_value=None, min_value=None)
DecimalFieldDecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置
DateTimeFieldDateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
DateFieldDateField(format=api_settings.DATE_FORMAT, input_formats=None)
TimeFieldTimeField(format=api_settings.TIME_FORMAT, input_formats=None)
DurationFieldDurationField()
ChoiceFieldChoiceField(choices) choices与Django的用法相同
MultipleChoiceFieldMultipleChoiceField(choices)
FileFieldFileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ImageFieldImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ListFieldListField(child=, min_length=None, max_length=None)
DictFieldDictField(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页面时,显示的字段帮助提示信息

定义序列化器

方式一:继承serializers.Serializer

  • 标准规则
    • 和模型类,字段名一样
    • 和模型类,字段类型一样
    • 和模型类,字段选项一样
    • 如果有入库操作,必须是实现create,update方法,内部默认没有实现这两个方法

普通字段

from rest_framework import serializers
class StudentSerializer(serializers.Serializer):
    period=serializers.IntegerField(default=0)
    username=serializers.CharField(max_length=10)
    password=serializers.CharField(max_length=16)

选项字段

from rest_framework import serializers
class StudentSerializer(serializers.Serializer):
    #方式一,获取对应数据库值
    period=serializers.IntegerField()
    
    #方式二,显示对应的中文,相当于obj.get_period_display()
    pk_name = serializers.CharField(source='get_period_display')
  • 注意事项
    • 如果与模型字段名不一样,需要使用参数source指定模型字段名
      如果有参数source,他会在内部默认执行:obj.period
      pk=serializers.CharField(source=‘period’)

一对多关系字段

  • 从表获取主表
#方式一,设置参数read_only=True   或者  设置queryset=article.objects.all()     	返回值只能是id值
article=serializers.PrimaryKeyRelatedField(read_only=True)
article=serializers.PrimaryKeyRelatedField(queryset=article.objects.all())

#方式二,使用模型类__str__方法获取      											返回值是 __str__的返回值
article=serializers.StringRelatedField(read_only=True)     

#方式三,使用article的序列化器													返回值是序列化器所有的字段
article=ArticleSerializer()

#方式四,使用source指定字段属性值											返回值获取对应一中的单个指定属性值
article_name=serializers.CharField(source='article.name')

#方式五,使用字段函数,格式def get_字段名(self,instance)   						返回值获取对应一中的多个指定属性值
article=serializers.SerializerMethodField()
def get_article(self,instance):
    article=instance.article
    return {'id':article.id,'name':article.name}
  • 主表获取从表
#方式一,设置参数read_only=True   或者  设置queryset=article.objects.all()     	返回值只能是id值
article_set=serializers.PrimaryKeyRelatedField(read_only=True,many=True)

#方式二,使用模型类__str__方法获取      											返回值是 __str__的返回值
article_set=serializers.StringRelatedField(read_only=True,many=True)     

#方式三,使用user的序列化器													返回值是序列化器所有的字段
article_set=ArticleSerializer(many=True)

#方式四,使用source指定字段属性值											返回值获取对应多中的单个指定属性值
article_name=serializers.CharField(source='article_set.name')

#方式五,使用字段函数,格式def get_字段名(self,instance)   						返回值获取对应多中的多个指定属性值
article=serializers.SerializerMethodField()
def get_article(self,instance):
    articles=instance.article_set.all()
    ret=[]
    for item in articles:
            ret.append({'id':item.id,'name':item.name})
    return ret

多对多关系字段

主表获取从表的多个属性值

course=serializers.SerializerMethodField()
def get_course(self,row):
    objs=row.course_set.all()
    ret=[]
    for item in objs:
        ret.append({'id':item.id,'name':item.name})
        return ret

从表获取主表的多个属性值

course=serializers.SerializerMethodField()
def get_course(self,row):
    objs=row.course.all()
    ret=[]
    for item in objs:
    ret.append({'id':item.id,'name':item.name})
    return ret

一对一关系同理

通过继承serializers.字段类型对字段返回值进行修改

class MyField(serializers.CharField):
    def to_representation(self, value):
        return 'new'+value
    
#序列化器中使用的时候,直接username = MyField()

如果有入库,必须实现create 实现update方法

def create(self,validated_data)#1,创建book对象,设置属性,入库
    book=BookInfo.objects.create(**validated_data)
    #2,返回
    return book

def update(self,instance,validated_data)#1,更新数据
    instande.btitle=validated_data["btitle"]
    #2,入库
    instance.save()
    #或者
    instance=instance.upadte(**validated_data)
    #3,返回
    return instance

方式二:继承serializers.ModelSerializer

  • 不用一个一个字段类型的声明了,指定模型之后,会自动根据模型帮助我们声明
  • 不用再重写入库方法create,update了,内部已经帮我们实现了
class StudentSerializer(serializers.ModelSerializer):
    username = MyField()
    # grade=serializers.HyperlinkedIdentityField(view_name='ds',lookup_field='Grade',lookup_url_kwarg='pk')
    class Meta:
        #需要序列化的模型
        model=Student
        
        #需要序列化的字段,“__all__”表示全部字段,列表中的字段也可以混合自定义字段
        # fields="__all__"
        fields=['username','password','Grade']
        
        #序列化的深度,这是针对一对一,一对多,多对多关系来说的,进行下一个对象的序列化,默认深度为0
        depth=0

Meta类其他属性:

  • read_only_fields
    • 如果希望多个字段是只读状态,可以使用这个快捷方式,一个列表,内部是字段名
  • extra_kwargs
    • 这是对字段的校验规则,如果在字段声明中已经有了,则会被忽略,这个只是作为额外补充。
  • exclude
    • 排除某些字段。

在视图中使用序列化器

serializer=UserModelSerializer(
	instance="对象(们)",
    data="数据(们)",
    many=False|True#与数据或对象配套,代表操作的是否是多个
    partial=False|True#运用在局部修改中,所以校验可以选填(required=False)
	context={'request':request}#视图、序列化传参
)

serializer.is_valid(raise_exception=False|True)#校验数据,(raise_exception如果为true,会抛出异常),结果返回布尔类型
serializer.save()			#入库操作,执行create或update方法
serializer.data				#序列化后的数据
serializer.errors			#校验失败的信息
  • 总结
    • 如果是序列化单个对象,只需要传递参数instance
    • 如果是序列化多个对象,不仅传递参数instance,还要传递many=true
    • 如果是反序列化创建一个对象,传递参数data ,最后serializer.save()入库
    • 如果是反序列化更新一个对象,传递参数instance,还有data,最后serializer.save()入库
    • 如果仅仅是想对数据进行校验,传递参数data

对字段进行自定义校验

1. 验证单个字段(validate_验证字段名)

说明:其实model层已经帮我们验证了一些字段,但是不能验证全,比如说 phone手机号,是11位,而且是以 13、15、等开头的规则,那咋办。这个时候我们就要用到 单个字段的验证(phone规则验证)。用法如下:

from rest_framework import serializers
from .models import User
import re
 
class UserSerializer(serializers.ModelSerializer):
    #因为phone没有办法支持11位,需重新定义phone规则。
    phone = serializers.CharField(max_length=11,min_length=11,required=True)
    class Meta:
        model = User
        fields = "__all__"
 
    #自定义单个字段验证规则:validate_验证字段名(phone),参数:传入的是当前字段(phone)
    #当我们序列化的时候,phone字段就会走自定义序列化函数
    def validate_phone(self, phone):
        #检测手机是否合法
        if not re.match(r'1[3456789]\d{9}',phone):
            raise serializers.ValidationError("手机号码不合法")  #如果不匹配我抛出一个异常
 
        #检测手机号是否存在
        if User.objects.filter(phone=phone).all():
            raise serializers.ValidationError("手机号已被注册")
 
        return phone  #一定要有返回值,意思就是把你验证后的字段返回给模型类

2. 组合字段验证(validate)

说明:我们有的时候需要验证两个字段,比如说,在注册的时候,需要输入密码,和输入确认密码,但是我们只需要保存一次即可,那这种情况咋办呐。这个时候我们就需要用到validate这种组合验证方式。

from rest_framework import serializers
from .models import User
import re
 
class UserSerializer(serializers.ModelSerializer):
    phone = serializers.CharField(max_length=11,min_length=11,required=True)
 
    #序列化一个新字段pwd1,只是我们这个字段的值不保存数据库,后续验证完毕之后需要删除
    pwd1 = serializers.CharField(max_length=64,write_only=True) #write_only表示必须要从前端传递过来
    class Meta:
        model = User
        fields = "__all__"
 
    def validate_phone(self, phone): #单个验证
        ....
 
    def validate(self, attrs): #组合验证
        #print(attrs)  #attrs是:OrderedDict([('phone', '13641929925'), ('pwd1', '1234'), ('name', 'gaogao'), ('gender', 1), ('pwd', '1234')])
        if attrs.get('pwd1') != attrs.get('pwd'):
            raise serializers.ValidationError("两次密码不一样")
        attrs.pop('pwd1') #验证完毕需要删除pwd1,因为pwd1在模型类User中没有这个字段
        return attrs #一定要有返回值

重写入库方法

  • 如果是继承serializers.Serializer的序列化器,有入库操作,必须实现入库方法

  • 如果是继承serializers.ModelSerializer的序列化器,可以根据需要重写入库方法

1. create

说明:我们在注册密码的时候,需要进行用户密码的加密再存放进数据库,这个时候就需要重写 create 方法。

from rest_framework import serializers
from .models import User
import re
 
class UserSerializer(serializers.ModelSerializer):
    ....
    class Meta:
        model = User
        fields = "__all__"
     
    def create(self, validated_data):
        #重写create方法,对密码加密完之后,再插入到数据库中
        ---
        user=User.objects.create(**validated_data)
        return user

2. update

def update(self, instance, validated_data):
       重写方法
	return super(TruckSerializer, self).update(instance, validated_data)

choices 单选字段序列化

说明:我们在model类中,有的时候会存choice这样的选项。如下:

from django.db import models
 
# Create your models here.
 
class User(models.Model):
    genders = ((1, '男'), (2, "女"))
    gender = models.IntegerField(choices=genders, verbose_name='性别')
    ...

很明显 只显示 1或者 2这样的数据,不是我们想要的,那我们咋办呐?两种办法:

方式一,序列化中重新定义gender字段

说明:根据source来源来定义字段,这种方式只能支持序列化,但是不支持反序列化,所以只能获取数据,但是不能创建数据。

from rest_framework import serializers
from .models import User
import re
 
class UserSerializer(serializers.ModelSerializer):
 
    gender = serializers.CharField(source='get_gender_display')  #根据source数据来源定义字段
 
    class Meta:
        model = User
        fields = "__all__"

方式二,重写 to_representation 方法

说明:前面我们也讲了,所有字段的显示,其实就是在 to_representation方法里面,那我们在 to_representation 方法重新定义 gender字段不就可以了。这样既支持序列化,也可以支持反序列化。

from rest_framework import serializers
from .models import User
import re
 
class UserSerializer(serializers.ModelSerializer):
 
    class Meta:
        model = User
        fields = "__all__"
        
 	#重写to_representation方法
    def to_representation(self, instance):  
        representation = super(UserSerializer, self).to_representation(instance)  #继承UserSerializer父类
        representation['gender'] = instance.get_gender_display()  #重新定义gender字段
 
        return representation

额外字段(解决出参时不显示密码字段)

说明:我们在入参的时候可能想输入一些参数,但是在出参的时候,不想显示一些参数,比如说,密码,不可能我注册的时候,响应给我密码多少。那这个怎么解决呐?我们就用额外字段解决。

from rest_framework import serializers
from .models import User
 
class UserSerializer(serializers.ModelSerializer):
 
    class Meta:
        model = User
        fields = "__all__"
        extra_kwargs = { #额外字段:改变我们字段的修饰
            "pwd": {"write_only": True}  #write_only: True 表示只允许入参,不允许出参
        }

Validators验证器

UniqueValidator:对象是唯一

说明:其实这个我们在model模型类中用unique=True 也可以验证。

username = serializers.CharField(
    required=True, allow_blank=False, label="用户名",max_length=16,min_length=6,
	validators=[UniqueValidator(queryset=User.objects.all(),message="用户已经存在")],
    error_messages={
        "blank": "用户名不允许为空",
        "required": "请输入用户名",
        "max_length": "用户名长度最长为16位",
        "min_length": "用户名长度至少为6位"
    })

UniqueTogetherValidator:联合唯一

说明:两个组合联合唯一

class UserFav(models.Model):
    user = models.ForeignKey(User,verbose_name="用户",on_delete=False)
    goods = models.ForeignKey(Goods,verbose_name="商品",on_delete=False)
    add_time = models.DateTimeField(default=datetime.now,verbose_name="用户收藏")
 
    class Meta:
        verbose_name = "用户收藏"
        verbose_name_plural=verbose_name
        unique_together = (('user','goods'),)
         
class UserFavSerializer(serializers.ModelSerializer):
    user = serializers.HiddenField(default=serializers.CurrentUserDefault())
 
    class Meta:
        model = UserFav
        fields = ('id','user', 'goods')
        validators = [UniqueTogetherValidator(queryset=UserFav.objects.all(),fields=('user','goods'),message='您已收藏')]

自定义Validators验证器

#校验类
class PasswordValidator(object):
    def __call__(self, value):
        if len(value)<=6:
            message = '密码太短'
            raise serializers.ValidationError(message)
    def set_context(self, serializer_field):
        """
        This hook is called by the serializer instance,
        prior to the validation call being made.
        """
        # 执行验证之前调用,serializer_fields是当前字段对象
        pass
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值