DRF之序列化类

一 序列化介绍

作用:

1.序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串

2.反序列化,把客户端发送过来的数据,经过response以后变成字典,序列化器可以把字典转成模型

3.反序列化,完成数据校验功能,前端传入数据,存到数据库中

1.1继承APIView+Response实现publish的五个接口

class PublishView(APIView):
    def get(self, request):
        publish_list = Publish.objects.all()
        l = []
        for publish in publish_list:
            l.append({'name': publish.name, 'addr': publish.addr})
        return Response({'code': 100, 'msg': '查询所有成功', 'results': l})

    def post(self, request):
        # 如果是urlencoded编码,这种方式不行 publish = Publish.objects.create(**request.data)
        publish = Publish.objects.create(name=request.data.get('name'), addr=request.data.get('addr'))
        return Response({'code': 100, 'msg': '新增成功', 'results': {'name': publish.name, 'addr': publish.addr}})


class PublishDetailView(APIView):
    def get(self, request, pk):
        publish = Publish.objects.filter(pk=pk).first()
        return Response(
            {'code': 100, 'msg': '查询单条成功', 'results': {'name': publish.name, 'addr': publish.addr}})

    def put(self, request, pk):
        publish = Publish.objects.filter(pk=pk).first()
        publish.name = request.data.get('name')
        publish.addr = request.data.get('addr')
        publish.save()
        return Response({'code': 100, 'msg': '修改成功', 'result': {'name': publish.name, 'addr': publish.addr}})

    def delete(self, request, pk):
        Publish.objects.filter(pk=pk).delete()
        return Response({'code': 100, 'msg': '删除成功'})

1.2 序列化的使用

我们可以使用def提供的序列化器,实现序列化,反序列化和数据校验

使用步骤

        1.写个py文件,叫serializer.py

        2.写个类,继承serializer.Serializer

        3.在类中写要序列化的代码

 class PublishSerializer(serializers.Serializer):
        # 写字段,要序列化的字段
        name = serializers.CharField()
        addr = serializers.CharField()
        id = serializers.IntegerField()

        4.在视图类中完成序列化

        多条

ser = PublishSerializer(instance=publish_list, many=True)
ser.data  # 序列化后的数据

        单条

ser = PublishSerializer(instance=publish)  	
ser.data  序列化后的数据

二 序列化类的快速使用

视图类

为了能够更加方便区分,我们把视图类的五个方法分到两个类中

from .serializer import PublishSerializer # 导入我们写好的serializer文件


class PublishView(APIView):
    def get(self, request):
        publish_list = Publish.objects.all()
        ser = PublishSerializer(instance=publish_list, many=True)  # 如果序列化多条,要many=True
        return Response({'code': 100, 'msg': '查询所有成功', 'results': ser.data})

class PublishDetailView(APIView):
    def get(self, request, pk):
        publish = Publish.objects.filter(pk=pk).first()
        ser = PublishSerializer(instance=publish)  # 单个不写many=True
        return Response(
            {'code': 100, 'msg': '查询单条成功', 'results': ser.data})

序列化类

from rest_framework import serializers
class PublishSerializer(serializers.Serializer):
    # 写字段,要序列化的字段
    name = serializers.CharField()
    # addr = serializers.CharField()
    id = serializers.IntegerField()

路由

urlpatterns = [
    path('publish/', views.PublishView.as_view()),
    path('publish/', views.PublishDetailView.as_view()),
]

三 序列化类反序列化校验

序列化类可以做字段校验,字段校验总共有三层

第一层:字段自己的,我们可以在字段中加入限制条件

serializers.CharField(max_length=12,min_length=3)

第二层:局部钩子

def validate_name(self, name):
    # 待校验的前端传入的name的数据
    if name.startswith("sb"):
   # 不行,抛异常
    raise ValidationError('不能以sb开头')
    return name

第三层:全局钩子

def validate(self, attrs):
    print(attrs)
    # 多个字段同时校验
    # 出版社名和地址不能一样---》出版社前3个字不能和地址前3个字一样
    if attrs.get('name')[:3] == attrs.get('addr')[:3]:
        raise ValidationError('出版社名和地址不能一样')
        return attrs

使用步骤

1.写序列化类:写三层规则

2.视图类中

    ser = PublishSerializer(data=request.data)  # 把待校验数据传入
    if ser.is_valid():  # 做数据校验---》三层
        print(ser.data)
	else:
		print(ser.errors)  # 没有校验通过,打印错误信息

四 序列化保存

使用步骤

1.在序列化类中,必须重写create,完成真正的保存

 # 保存,必须重写create
        def create(self, validated_data):
            # validated_data 校验过后的数据---》多传的数据,在这没有
            publish = Publish.objects.create(**validated_data)
            return publish  # 不要忘了返回新增的对象---》后续会拿着这个对象做序列化  ser.data--->根据它做序列化的

2.在视图类中,数据校验通过后,调用ser.save()

ser.save()  # 使用序列化类保存--》会报错---》咱们没有指定保存到那个表--》必须重写create方法

3.修改功能,也要校验和保存

修改使用步骤

1 在序列化类中,必须重写 update,完成真正的修改

def update(self, instance, validated_data):  # {name:上海出版社,add:上海地址}
    instance.name=validated_data.get('name')
    instance.addr=validated_data.get('addr')
    instance.save() # publish 对象的save---》保存到数据中
    return instance

2.视图类中

		ser = PublishSerializer(instance=publish, data=request.data)
		ser.save() # 虽然新增或修改都是调用save,但是内部做了判断

五 序列化常用字段

序列化的常用字段除了CharField之外基本上与我们django中的model层中的字段基本一一对应

字段 字段构造方式
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'"5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"
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)
ListField ListField(child=, min_length=None, max_length=None)
DictField DictField(child=)

六 序列化字段常用参数

字段参数

# CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
	max_length :校验,最大长度
    min_length:校验最短长度
    allow_blank:是否允许为空
    trim_whitespace:去掉前后的空白
    
    
# DateTimeField(format=api_settings.DATETIME_FORMAT)
	format:格式化成的样子
    
# IntegerField(max_value=None, min_value=None)
	max_value :数字
    min_value:数字

通用参数

read_only    表明该字段仅用于序列化输出,默认False
write_only    表明该字段仅用于反序列化输入,默认False
-------------------------------------------------------
required    表明该字段在反序列化时必须输入,默认True
default         反序列化时使用的默认值
allow_null     表明该字段是否允许传入None,默认False
validators     该字段使用的验证器:validators=[方法],方法对该字段做校验
error_messages    包含错误编号与错误信息的字典
---------------
label         用于HTML展示API页面时,显示的字段名称
help_text     用于HTML展示API页面时,显示的字段帮助提示信息

七 序列化高级用法之定制返回字段

定制序列化返回的字段格式

方案一:在表模型中写,在序列化类中映射  (可以使用source)

        # models.py
        def publish_detail(self):
        	return {'name': self.publish.name, 'city': self.publish.city}
        # serializer.py
        	publish_detail = serializers.DictField()
        # 前端看到
            "publish_detail": {
                "name": "北京出版本是",
                "city": "北京"
            }

方案二:在序列化类中写SerializerMethodField,必须配合一个方法 get_字段名,方法返回什么,前端就看到什么

        # Serializer.py
            publish_detail = serializers.SerializerMethodField()
            def get_publish_detail(self, obj):
                return {'name': obj.publish.name, 'city': obj.publish.city}
        # 前端看到
            "publish_detail": {
                "name": "北京出版本是",
                "city": "北京"
            }

model.py

from django.db import models


class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)

    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    authors = models.ManyToManyField(to='Author')

    def __str__(self):
        return self.name
    # def book_name(self):
    #     return self.name+'sb'
    # def publish_detail(self):
    #     return {'name': self.publish.name, 'city': self.publish.city}
    #
    # def author_list(self):
    #     l = []
    #     for author in self.authors.all():
    #         l.append({'name': author.name, 'age': author.age})
    #     return l


class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)

    def __str__(self):
        return self.name


class AuthorDetail(models.Model):
    telephone = models.BigIntegerField()
    birthday = models.DateField()
    addr = models.CharField(max_length=64)


class Publish(models.Model):
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = '出版社'
        verbose_name_plural = verbose_name

views.py

class BookView(APIView):
    def get(self, request):
        obj = Book.objects.all()
        ser = BookSerializer(instance=obj, many=True)

        '''
        [
            {
                "name": "西游记",
                "price": "66.00",
                "publish_detail": {name:名字,city:城市},
                "authors_list":[{name:名字,age:19}]
            },
    
        ]
        
        '''
        return Response(ser.data)

serializer.py

### 定制返回字段
class BookSerializer(serializers.Serializer):
    name = serializers.CharField()
    price = serializers.CharField()
    #### 定制返回字段---》方案一:在表模型中写方法,在序列化类中做映射
    # publish_detail = serializers.CharField()  # publish_detail 会映射表模型中 publish_detail方法,方法返回值是 字典,强行用CharField字符串接收
    # publish_detail = serializers.DictField()  # publish_detail 会映射表模型中 publish_detail方法,方法返回值是 字典,用DictField接收
    # author_list = serializers.ListField()

    ###定制返回字段---》方案二:在序列化类中写  SerializerMethodField
    # 只要写了这个字段类SerializerMethodField,必须配合一个方法:get_字段名,这个方法返回什么,前端这个字段就显示什么
    publish_detail = serializers.SerializerMethodField()

    def get_publish_detail(self, obj):
        # 当前序列化到的book对象
        return {'name': obj.publish.name, 'city': obj.publish.city}

    author_list = serializers.SerializerMethodField()

    def get_author_list(self, obj):
        l = []
        for author in obj.authors.all():
            l.append({'name': author.name, 'age': author.age})
        return l

    book_name = serializers.SerializerMethodField()
	
    def get_book_name(self, obj):
        return obj.name + 'sb'

你可能感兴趣的:(python,django)