序列化操作:
序列化是将后端响应数据转换成JSON数据给客户端(PC端、APP端)
一、获取单条数据(序列化)
from app1.models import NewsChannel
from app1.serializer import NewsChannelSerializer
#获取模型对象
channel_obj=NewsChannel.objects.get(id=1)
#创建序列化器对象
serializer=NewsChannelSerializer(instance=channel_obj)
#获取模型对象的数据
serializer.data
二、获取多条数据(序列化)
many=True
from app1.models import NewsChannel
from app1.serializer import NewsChannelSerializer
#获取查询集对象
channel_list=NewsChannel.objects.all()
#创建序列化器对象
serializer=NewsChannelSerializer(instance=channel_list,many=True)
#获取模型对象的数据
serializer.data
三、关联对象嵌套序列化
如果当前序列化器中涉及关联对象,⽐如涉及外键字段。那么关联对象序列器需要定义。
例如:如下模型类
from django.db import models
# Create your models here.
class NewsChannel(models.Model):
'''新闻频道'''
name=models.CharField(max_length=30,unique=True,verbose_name='频道名称')
url=models.CharField(default='',null=True,blank=True,max_length=50,verbose_name='频道页面链接')
class Meta:
db_table='app2_news_channel'
verbose_name='新闻频道'
verbose_name_plural=verbose_name
def __str__(self):
return self.name
class NewsCategory(models.Model):
'''新闻类别'''
name=models.CharField(max_length=10,verbose_name='名称')
sequence=models.IntegerField(verbose_name='排序')
channel=models.ForeignKey(NewsChannel,on_delete=models.PROTECT)
class Meta:
db_table='app2_news_category'
verbose_name='新闻类别'
verbose_name_plural=verbose_name
def __str__(self):
return self.name
PrimaryKeyRelatedField
定义序列化器类
from rest_framework import serializers
from rest_framework.relations import PrimaryKeyRelatedField
from app2.models import *
class NewsChannelSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True, label='ID')
name = serializers.CharField(max_length=30, label='name')
url = serializers.CharField(max_length=50, label='url')
class NewsCategorySerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True, label='ID')
name = serializers.CharField(max_length=10, label='name')
sequence = serializers.IntegerField(label='sequence')
channel=serializers.PrimaryKeyRelatedField(label='类别关联id',help_text='类别关联id',read_only=True)
测试结果:
StringRelatedField
from rest_framework import serializers
from rest_framework.relations import PrimaryKeyRelatedField
from app2.models import *
class NewsChannelSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True, label='ID')
name = serializers.CharField(max_length=30, label='name')
url = serializers.CharField(max_length=50, label='url')
class NewsCategorySerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True, label='ID')
name = serializers.CharField(max_length=10, label='name')
sequence = serializers.IntegerField(label='sequence')
channel=serializers.StringRelatedField(label='类别关联id',help_text='类别关联id',read_only=True)
测试结果:
使⽤关联对象的序列化器对象
from rest_framework import serializers
from rest_framework.relations import PrimaryKeyRelatedField
from app2.models import *
class NewsChannelSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True, label='ID')
name = serializers.CharField(max_length=30, label='name')
url = serializers.CharField(max_length=50, label='url')
newscategory_set=PrimaryKeyRelatedField(label='频道关联id',help_text='频道关联id',many=True,read_only=True)
class NewsCategorySerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True, label='ID')
name = serializers.CharField(max_length=10, label='name')
sequence = serializers.IntegerField(label='sequence')
channel=NewsChannelSerializer(label='类别关联id',help_text='类别关联id',read_only=True)
测试结果:
其他(如果关联对象数据包含多条记录)
PrimaryKeyRelatedField
from rest_framework import serializers
from rest_framework.relations import PrimaryKeyRelatedField
from app2.models import *
class NewsChannelSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True, label='ID')
name = serializers.CharField(max_length=30, label='name')
url = serializers.CharField(max_length=50, label='url')
newscategory_set=PrimaryKeyRelatedField(label='频道关联id',help_text='频道关联id',many=True,read_only=True)
class NewsCategorySerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True, label='ID')
name = serializers.CharField(max_length=10, label='name')
sequence = serializers.IntegerField(label='sequence')
channel=NewsChannelSerializer(label='类别关联id',help_text='类别关联id',read_only=True)
测试结果:
StringRelatedField
from rest_framework import serializers
from rest_framework.relations import StringRelatedField
from app2.models import *
class NewsChannelSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True, label='ID')
name = serializers.CharField(max_length=30, label='name')
url = serializers.CharField(max_length=50, label='url')
newscategory_set=StringRelatedField(label='频道关联id',help_text='频道关联id',many=True,read_only=True)
class NewsCategorySerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True, label='ID')
name = serializers.CharField(max_length=10, label='name')
sequence = serializers.IntegerField(label='sequence')
channel=NewsChannelSerializer(label='类别关联id',help_text='类别关联id',read_only=True)
测试结果:
CategorySerializer
from rest_framework import serializers
from rest_framework.relations import PrimaryKeyRelatedField
from rest_framework.relations import StringRelatedField
from app2.models import *
from app2.serializers1 import NewsCategorySerializer
class NewsCategorySerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True, label='ID')
name = serializers.CharField(max_length=10, label='name')
sequence = serializers.IntegerField(label='sequence')
class NewsChannelSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True, label='ID')
name = serializers.CharField(max_length=30, label='name')
url = serializers.CharField(max_length=50, label='url')
newscategory_set=NewsCategorySerializer(label='频道关联id',help_text='频道关联id',many=True,read_only=True)
测试结果:
>>> from app2.models import *
>>> from app2.serializers2 import *
>>> object=NewsChannel.objects.get(id=1)
>>> serializer=NewsChannelSerializer(instance=object)
>>> serializer.data
{'id': 1, 'name': '科技', 'url': '/keji/', 'newscategory_set': [OrderedDict([('id', 1), ('name', '软件'), ('sequence', 1)]), OrderedDict([('id', 2), ('name', '互联网'), ('sequence', 2)]), OrderedDict([('id', 3), ('name', '智能家居'), ('sequence', 3)])]}
反序列化操作
反序列化是将前端数据转换成django模型类对象类型,对数据库进⾏操作。
反序列化实现流程:验证–> 保存/更新数据
一、验证
使⽤序列化器进⾏反序列化时,需要对数据进⾏验证后,才能获得验证成功的数据或保存成模型类对象。
在获取反序列化的数据前,必须调⽤is_valid()⽅法进⾏验证,验证成功返回True,否则返回False。
验证失败,可以通过序列化器对象的错误属性获取错误信息,返回字典,包含了分段和对⻬的错误。如果是⾮字符串错误,可以通过修改REST框架配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。
验证成功,可以通过序列化器对象的validated_data属性获取数据。
在定义序列化器时,指定每个⽚段的序列化类型和选项参数,本身就是⼀种验证⾏为。
如下
from rest_framework import serializers
from app2.models import *
class NewsCategorySerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True, label='ID')
name = serializers.CharField(max_length=10, label='name')
sequence = serializers.IntegerField(label='sequence')
class NewsChannelSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True, label='ID')
name = serializers.CharField(max_length=30, label='name')
url = serializers.CharField(max_length=50, label='url')
newscategory_set=NewsCategorySerializer(label='频道关联id',help_text='频道关联id',many=True,read_only=True)
测试结果:字段校验不通过时
>>> from app2.models import *
>>> from app2.serializers2 import *
>>> data={'name':8888}
>>> serializer=NewsChannelSerializer(data=data)
>>> serializer.is_valid()
False
>>> serializer.errors
{'url': [ErrorDetail(string='This field is required.', code='required')]}
>>> serializer.validated_data
{}
测试结果:字段校验通过时
>>> data={"name":8888,"url":"/redian/"}
>>> serializer=NewsChannelSerializer(data=data)
>>> serializer.is_valid()
True
>>> serializer.errors
{}
>>> serializer.validated_data
OrderedDict([('name', '8888'), ('url', '/redian/')])
is_valid()⽅法还可以在验证失败时抛出异常serializers.ValidationError
可以通过传递raise_exception = True参数开启,REST框架接收到此异常,会向前端返回HTTP 400 Bad Request响应。
serializer.is_valid(raise_exception=True)
如果觉得这些还不够,需要再补充定义验证⾏为,可以使⽤以下三种⽅法:
validate_<field_name>⽅法:针对某个字段校验
from rest_framework import serializers
from app2.models import *
class NewsChannelSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True, label='ID')
name = serializers.CharField(max_length=30, label='name')
url = serializers.CharField(max_length=50, label='url')
#针对某个字段校验
def validate_name(self,value):
if 'tt_' not in value.lower():
raise serializers.ValidationError('频道名词不包含tt_')
return value
测试结果:
>>> from app2.serializers1 import *
>>> data={"name":"体育","url":"/sports/"}
>>> serializer=NewsChannelSerializer(data=data)
>>> serializer.is_valid()
False
>>> serializer.errors
{'name': [ErrorDetail(string='频道名词不包含_', code='invalid')]}
validate⽅法:针对多个字段进行校验
from rest_framework import serializers
from app2.models import *
class NewsChannelSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True, label='ID')
name = serializers.CharField(max_length=30, label='name')
url = serializers.CharField(max_length=50, label='url')
#针对某个字段校验
def validate_name(self,value):
if 'tt_' not in value.lower():
raise serializers.ValidationError('频道名词不包含tt_')
return value
#对多个字段进行校验
def validate(self,attrs):
name=attrs['name']
url=attrs['url']
if len(name)>len(url):
raise serializers.ValidationError('name长度大于url长度')
return attrs
测试结果:
>>> from app2.serializers1 import *
>>> data={"name":"tt_抗击疫情,人人有责","url":"/yiqing/"}
>>> serializer=NewsChannelSerializer(data=data)
>>> serializer.is_valid()
False
>>> serializer.errors
{'non_field_errors': [ErrorDetail(string='name长度大于url长度', code='invalid')]}
validators属性:在字段中添加validators选项参数,也可以补充验证⾏为
from rest_framework import serializers
from app2.models import *
def va_name(value):
if 'tt_' not in value.lower():
raise serializers.ValidationError('频道名词不包含t_')
return value
class NewsChannelSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True, label='ID')
name = serializers.CharField(validators=[va_name],max_length=30, label='name')
url = serializers.CharField(max_length=50, label='url')
#针对某个字段校验
def validate_name(self,value):
if 'tt_' not in value.lower():
raise serializers.ValidationError('频道名词不包含tt_')
return value
#对多个字段进行校验
def validate(self,attrs):
name=attrs['name']
url=attrs['url']
if len(name)>len(url):
raise serializers.ValidationError('name长度大于url长度')
return attrs
测试结果:
>>> from app2.serializers1 import *
>>> data={"name":"抗击疫情,人人有责","url":"/yiqing/"}
>>> serializer=NewsChannelSerializer(data=data)
>>> serializer.is_valid()
False
>>> serializer.errors
{'name': [ErrorDetail(string='频道名词不包含t_', code='invalid')]}
>>> serializer.validated_data
{}
保存/更新数据
如果在验证成功后,想要基于validated_data完成数据对象的创建,可以通过实现create()和update()两个⽅法来实现。
def va_name(value):
if '_' in value.lower():
raise serializers.ValidationError('频道名词包含t_')
return value
class NewsChannelSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True, label='ID')
name = serializers.CharField(validators=[va_name],max_length=30, label='name')
url = serializers.CharField(max_length=50, label='url')
#针对某个字段校验
def validate_name(self,value):
if 't' in value.lower():
raise serializers.ValidationError('频道名词包含t')
return value
#对多个字段进行校验
def validate(self,attrs):
name=attrs['name']
url=attrs['url']
if len(name)>len(url):
raise serializers.ValidationError('name长度大于url长度')
return attrs
def create(self, validated_data):
channel_object=NewsChannel(**validated_data)
return channel_object
def update(self, instance, validated_data):
instance.name=validated_data.get('name',instance.name)
instance.url=validated_data.get('url',instance.url)
instance.save()
return instance
测试结果:创建数据
>>> from app2.serializers1 import *
>>> data={"name":"疫情","url":"/yiqing/"}
>>> serializer=NewsChannelSerializer(data=data)
>>> serializer.is_valid()
True
>>> serializer.validated_data
OrderedDict([('name', '疫情'), ('url', '/yiqing/')])
>>> serializer.save()
<NewsChannel: 疫情>
测试结果:更新数据
>>> from app2.serializers import *
>>> object=NewsChannel.objects.get(id=1)
>>> data={"name":"疫情","url":"/yiqing/"}
>>> serializer=NewsChannelSerializer(instance=object,data=data)
>>> serializer.is_valid()
True
>>> serializer.validated_data
OrderedDict([('name', '疫情'), ('url', '/yiqing/')])
>>> serializer.save()
<NewsChannel: 疫情>
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/74060.html