【DRF】序列化和反序列化操作(4)

导读:本篇文章讲解 【DRF】序列化和反序列化操作(4),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

序列化操作:

序列化是将后端响应数据转换成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

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!