Serializer的使用

【一】常用序列化字段和参数

【1】常见字段

字段 详解 字段构造方式
BooleanField 布尔字段用于存储和表示真/假值。构造方法不需要参数。 BooleanField()
NullBooleanField 可空布尔字段是可以接受三个值的布尔字段:True、False和None(空值)。构造方法不需要参数。 NullBooleanField()
CharField 字符字段用于存储短文本数据。max_length指定字符的最大长度,min_length指定最小长度。allow_blank指定是否允许为空值。trim_whitespace指定是否在保存数据前去除首尾的空格。 CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
EmailField Email字段用于存储和验证电子邮件地址。max_length指定最大字符长度,min_length指定最小长度。allow_blank指定是否允许为空值。 EmailField(max_length=None, min_length=None, allow_blank=False)
RegexField 正则表达式字段用于存储和验证符合特定模式的数据。regex指定正则表达式,max_length指定最大字符长度,min_length指定最小长度。allow_blank指定是否允许为空值。 RegexField(regex, max_length=None, min_length=None, allow_blank=False)
SlugField Slug字段用于存储URL友好的文本标识符。max_length指定最大字符长度,min_length指定最小长度。allow_blank指定是否允许为空值。 SlugField(max_length=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9_-]+
URLField URL字段用于存储和验证URL地址。max_length指定最大字符长度,min_length指定最小长度。allow_blank指定是否允许为空值。 URLField(max_length=200, min_length=None, allow_blank=False)
UUIDField UUID字段用于存储和验证通用唯一标识符。format参数指定UUID的格式。 UUIDField(format='hex_verbose') format: 1) 'hex_verbose'"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex'"5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "1234567012312313134124512351145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"
IPAddressField IP地址字段用于存储和验证IP地址。protocol参数指定所允许的IP地址协议类型,unpack_ipv4参数指定是否拆分IPv4地址。 IPAddressField(protocol='both', unpack_ipv4=False, **options)
IntegerField 整数字段用于存储整数值。max_value指定最大值,min_value指定最小值。 IntegerField(max_value=None, min_value=None)
FloatField 浮点数字段用于存储浮点数值。max_value指定最大值,min_value指定最小值。 FloatField(max_value=None, min_value=None)
DecimalField 十进制字段用于存储精确的十进制数值。max_digits指定最多位数,decimal_places指定小数点位置。coerce_to_string指定是否将值强制转化为字符串形式。max_value指定最大值,min_value指定最小值。 DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置
DateTimeField 日期时间字段用于存储日期和时间。format参数指定日期时间的输出格式,input_formats参数指定输入格式。 DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
DateField 日期字段用于存储日期。format参数指定日期的输出格式,input_formats参数指定输入格式。 DateField(format=api_settings.DATE_FORMAT, input_formats=None)
TimeField 时间字段用于存储时间。format参数指定时间的输出格式,input_formats参数指定输入格式。 TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
DurationField 持续时间字段用于存储一段时间的持续时间。构造方法不需要参数。 DurationField()
ChoiceField 选择字段用于存储和验证预定义选项中的一个值。choices参数指定可选的选项值。 ChoiceField(choices) choices与Django的用法相同
MultipleChoiceField 多选字段用于存储和验证多个预定义选项中的值。choices参数指定可选的选项值。 MultipleChoiceField(choices)
FileField 文件字段用于上传和保存文件。max_length指定文件名的最大长度,allow_empty_file指定是否允许为空文件。use_url指定是否使用文件的URL路径。 FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ImageField 图片字段用于上传和保存图片文件。max_length指定文件名的最大长度,allow_empty_file指定是否允许为空文件。use_url指定是否使用图片的URL路径。 ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ListField 列表字段用于存储和验证列表类型的数据。child参数指定列表中元素的类型,min_length指定最小长度,max_length指定最大长度。 ListField(child=, min_length=None, max_length=None)
DictField 字典字段用于存储和验证字典类型的数据。child参数指定字典中value的类型。 DictField(child=)
  • 总结:常用字段
IntegerField      
CharField   
DateTimeField  
DecimalField

ListField和DictField

【2】字段参数(校验数据)

(1)选项参数:(CharField,IntegerField)

参数名称 作用
max_length 最大长度
min_lenght 最小长度
allow_blank 是否允许为空
trim_whitespace 是否截断空白字符
max_value 最小值
min_value 最大值

(2)通用参数:

参数名称 说明
read_only 表明该字段仅用于序列化输出,默认False
write_only 表明该字段仅用于反序列化输入,默认False
required 表明该字段在反序列化时必须输入,默认True
default 反序列化时使用的默认值
allow_null 表明该字段是否允许传入None,默认False
  • 常用 参数

    read_only   
    write_only
    

【四】反序列化之校验(post增加,局部钩子,全局钩子)

  • 序列化类
class BookSerializer(serializers.Serializer):
    # 要序列化的字段
    # required : 是否必填字段,默认为True,就是必填字段
    id = serializers.IntegerField(required=False)
    # allow_blank:传入的数据允许为空,默认不为空
    # max_length: 限制字符串的最大长度
    name = serializers.CharField(allow_blank=True,max_length=8)
    # max_value:限制最大值
    # min_value:限制最小值
    # error_messages:自定义错误信息
    price = serializers.IntegerField(max_value=100, min_value=10, error_messages={"error": "价格必须在10-100之间"})
  • 后端使用
# 新增
def post(self, request):
    # 前端传入数据,通过request.data取到数据,将数据保存到数据库中
    # 借助于序列化类,完成校验和反序列化
    # data : 前端传入的数据
    book_ser = BookSerializer(data=request.data)
    # 校验数据
    if book_ser.is_valid():
        # 三层:字段自己的校验/全局钩子校验/局部钩子校验
        # 校验通过,保存数据
        # validated_data:校验通过的数据
        # 新增字段限制条件 ---> 在序列化类中的字段中添加限制条件
        after_data = book_ser.validated_data
    else:
        print(book_ser.errors)  # 校验失败的错误打印出来
        return Response({"code": 100, "msg": "成功"})

小结:反序列化有三层校验

  • 字段自己的:写的字段参数:required/max_length ...

  • 局部钩子:写在序列化类中的方法

    • 方法名必须是 validate_字段名
    def validate_name(self, name):
        if 'sb' in name:
            # 不合法,抛异常
            raise ValidationError('书名中不能包含sb')
        else:
            return name
    
  • 全局钩子:写在序列化类中的方法

    • 方法名必须是 validate
    def validate(self, attrs):
        price = attrs.get('price')
        name = attrs.get('name')
        if name == price:
            raise ValidationError('价格不能等于书名')
        else:
            return attrs
    
  • 只有三层都通过,在视图类中:

    • ser.is_valid(): 才是True,才能保存

【五】反序列化之保存(增加)

  • 新增接口
    • 数据校验后
    • 调用序列化类的 .save()方法
    • 同时还要在序列化类中重写 create 方法
  • 序列化类
class BookSerializer(serializers.Serializer):
    # 要序列化的字段
    # required : 是否必填字段,默认为True,必填字段
    id = serializers.IntegerField(required=False)
    # allow_blank:传入的数据允许为空,默认不为空
    # max_length: 限制字符串的最大长度
    name = serializers.CharField(allow_blank=True, max_length=8)
    # max_value:限制最大值
    # min_value:限制最小值
    # error_messages:自定义错误信息
    price = serializers.IntegerField(max_value=100, min_value=10, error_messages={"error": "价格必须在10-100之间"})
	
    def create(self, validated_data):
        # validated_data 校验过后的数据
        # **validated_data : 解耦,将数据打散
        book = models.Book.objects.create(**validated_data)
        return book
  • 后端使用
# 新增
def post(self, request):
    # 前端传入数据,通过request.data取到数据,将数据保存到数据库中
    # 借助于序列化类,完成校验和反序列化
    # data : 前端传入的数据
    book_ser = BookSerializer(data=request.data)
    # 校验数据
    if book_ser.is_valid():
        # 三层:字段自己的校验/全局钩子校验/局部钩子校验
        # 校验通过,保存数据
        # validated_data:校验通过的数据
        # 新增字段限制条件 ---> 在序列化类中的字段中添加限制条件
        after_data = book_ser.validated_data
        ser.save()  # 会保存数据,但是会报错,因为不知道要保存到哪张表中
        return Response({"code": 100, "msg": "成功"})
    else:
        print(book_ser.errors)  # 校验失败的错误
        return Response({"code": 100, "msg": "失败", "error": book_ser.errors})
  • 小结
    • 序列化类中重写 create 方法
    • 在后端逻辑中调用 save 方法
    • 如果调用create方法,校验通过的 validated_data 数据不会自动传入
    • 需要传入的数据 ser = BookSerializer(data=request.data)

【六】反序列化之保存(修改)

【1.0】指定字段修改数据

  • 序列化类
class BookSerializer(serializers.Serializer):
    # 要序列化的字段
    # required : 是否必填字段,默认为True,必填字段
    id = serializers.IntegerField(required=False)
    name = serializers.CharField(allow_blank=True, max_length=8)
    price = serializers.IntegerField(max_value=100, min_value=10, error_messages={"error": "价格必须在10-100之间"})

    def update(self, instance, validated_data):
        # instance : 需要修改的对象 --- book
        # validated_data : 需要修改并且是校验过的数据
        instance.name = validated_data.get('name')
        instance.price = validated_data.get('price')
        # 修改完要保存数据
        instance.save()
  • 后端使用
class BookDetailView(APIView):
    # 修改
    def put(self, request, pk):
        book = Book.objects.get(pk=pk)
        #instance 就是 BookSerializer.objects.get(pk=1) 返回的对象。
        ser = BookSerializer(instance=book, data=request.data)
        if ser.is_valid():
            ser.save()  # 也会报错,需要重写 update 方法
            return Response({"code": 100, "msg": "修改成功"})
        else:
            return Response({"code": 100, "msg": "修改失败", "error": book_ser.errors})
  • 问题就是
    • 在重写 update 方法的时候,需要一个个的去取字段然后做修改
    • 当字段太多的时候,会大大影响效率

【七】多字段案例

  • model表
from django.db import models


# Create your models here.
class Book(models.Model):
    name = models.CharField(max_length=32, db_index=True)
    price = models.IntegerField(unique=True)
    pub_date = models.DateField(auto_now=True)
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    authors = models.ManyToManyField("Author")

    def __str__(self):
        return self.name

    class Meta:
        db_table = 'book'


class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)

    def __str__(self):
        return self.name

    class Meta:
        db_table = 'publish'


class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    email = models.EmailField()

    def __str__(self):
        return self.name

    class Meta:
        db_table = 'author'

【1】多表关联反序列化(获取)

  • serializer类
from rest_framework import serializers


class PublishSerializer(serializers.Serializer):
    name = serializers.CharField()
    addr = serializers.CharField()


class AuthorSerializer(serializers.Serializer):
    name = serializers.CharField()
    age = serializers.IntegerField()
    email = serializers.EmailField()


class BookSerializer(serializers.Serializer):
    name = serializers.CharField()
    price = serializers.IntegerField()
    pub_date = serializers.DateField()
    # 序列化
    publish_detail = PublishSerializer(source='publish', read_only=True)
    author_list = AuthorSerializer(many=True, source='authors', read_only=True)
    # 反序列化
    publish = PublishSerializer(write_only=True)
    author = PublishSerializer( write_only=True)
  • views.py
from django.shortcuts import render
from rest_framework.response import Response
from .serializer import BookSerializer
from rest_framework.views import APIView

from task_xu.models import Book

class BookView(APIView):
    def get(self, request):
        books = Book.objects.all()
        # BookSerializer实例来序列化查询
        serializer = BookSerializer(instance=books, many=True)
        return Response(serializer.data)
image-20240412172703281

【1】多表关联反序列化(保存)

  • 不要有误区---》增加图书,只是增加图书,选择作者和出版社(传:id)
book_obj.add(*列表)
book_obj.authors.remove()      # 将某个特定的对象从被关联对象集合中去除。 
book_obj.authors.clear()       #清空被关联对象集合
book_obj.authors.set(列表)         #先清空再设置
read_only write_only 控制序列化类中某些字段,只用来序列化或反序列化
  • serializer类
class BookSerializer(serializers.Serializer):
    name = serializers.CharField()
    price = serializers.DecimalField(max_digits=5, decimal_places=2)
    publish_date = serializers.DateField(required=False,default=datetime.now)
    #### 序列化的字段和反序列化字段不一致####
    ## 1 笨办法:再写个序列化类,单独用来反序列化
    ## 2 通过 read_only write_only	控制

    # 这个字段用来做序列化
    publish_detail = PublishSerializer(source='publish',read_only=True)
    # 这个字段用来做序列化
    authors_list = AuthorSerializer(source='authors', many=True,read_only=True)

    # 反序列化字段--》只用来保存---》多表关联
    publish=serializers.IntegerField(write_only=True) # 前端传入数字---》自动跟出版社id做对应
    authors=serializers.ListField(write_only=True)
   
    # 更新
    def update(self, instance, validated_data):
        # 这些值将用于后续的单独更新操作
        publish_id = validated_data.pop('publish')
        authors=validated_data.pop('authors')
        # 使用instance直接作为filterDjango会自动提取并使用其主键值。
        book_qs=Book.objects.filter(pk=instance.pk)
        # 对非多对多关系字段的批量更新
        book_qs.update(**validated_data,publish_id=publish_id)
        # 获取查询集中的第一条记录
        # < QuerySet[ < Book: asdas >] >
        # instance = book_qs
        instance=book_qs.first()
        # 会在中间表中删除这些原有的关联记录,从而“清除”它们建立新的关联
        instance.authors.set(authors)
        return instance
  • views.py
class BookDetailView(APIView):

    def put(self, request, pk):
        # obj = Book.objects.all().filter(pk=pk).first()
        # 传入的instance是什么,到了 update中,instance就是什么
        serializer = BookSerializer(instance=pk, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response('成功')
        else:
            return Response({'code': 100, 'msg': serializer.errors})
posted @ 2024-04-17 22:08  -半城烟雨  阅读(7)  评论(0编辑  收藏  举报