---- the Serializer the DRF three streams (partial bottom)

Three streams: Complementary knowledge

import sys
# 标准输出流
sys.stdout.write('123') # print() 会换行 但是stdout不换
sys.stdout.write('123\n')

# 标准输入流
res = sys.stdin.readline()
print(res)

# 标准错误流
sys.stderr.write('123') # 结果是红色的 异步执行 123 永远比321先打印
sys.stderr.write('321') 

Serialization family

"""
1、Serializer类:底层序列化类 - 了解类
    重点:单表序列化

2、ModelSerializer类:模型序列化类 - 核心类
    重点:多表序列化
    
3、ListSerializer类:群操作序列化类 - 辅助类
    重点:辅助完成单表多表群增群改操作
"""

Knowledge points: Serializer(partial bottom), ModelSerializer(emphasis), ListModelSerializer(auxiliary group to change)

The Serializer (partial bottom)

1.instance and data parameters

1)用于序列化时,将模型类对象传入instance参数

2)用于反序列化时,将要被反序列化的数据传入data参数

3)除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据,如
# serializer = AccountSerializer(account, context={'request': request})

models.py ready

class User(models.Model):
    SEX_CHOICES = [
        [0, '男'],
        [1, '女'],
    ]
    name = models.CharField(max_length=64)
    pwd = models.CharField(max_length=32)
    phone = models.CharField(max_length=11, null=True, default=None)
    sex = models.IntegerField(choices=SEX_CHOICES, default=0)
    icon = models.ImageField(upload_to='icon', default='icon/default.jpg')

    class Meta:
        db_table = 'old_boy_user'
        verbose_name = '用户'
        verbose_name_plural = verbose_name

    def __str__(self):
        return '%s' % self.name

2. Serialization

1) Set who need to return to the foreground model class has a corresponding field, no return would not have provided

2) Setting method field, the field names are free, the field value is provided by the field name get_ methods, need to do some processing of data returned ( 如choice字段)

Custom serializer

Create a custom py files, customserializer

# 序列化组件 - 为每一个model类提供一套序列化工具类
# 序列化组件的工作方式与django froms组件非常相似
from rest_framework import serializers, exceptions
from django.conf import settings

from . import models

# 自定义后继承Serializer
class UserSerializer(serializers.Serializer):
    name = serializers.CharField()
    phone = serializers.CharField()
    # 序列化提供给前台的字段个数由后台决定,可以少提供,
    # 但是提供的数据库对应的字段,名字一定要与数据库字段相同
    # sex = serializers.IntegerField() 得到的结果不是自己想要的
    # icon = serializers.ImageField()

Like genderand iconfield sequence method:

第一种方法

    # 自定义序列化属性
    # 属性名随意,值由固定的命名规范方法提供:
    # get_属性名(self, 参与序列化的model对象)
    # 返回值就是自定义序列化属性的值
    gender = serializers.SerializerMethodField()
    def get_gender(self, obj):
        # choice类型的解释型值 get_字段_display() 来访问
        return obj.get_sex_display()
    
    icon = serializers.SerializerMethodField()
    def get_icon(self, obj):
        # settings.MEDIA_URL: 自己配置的 /media/,给后面高级序列化与视图类准备的
        # obj.icon不能直接作为数据返回,因为内容虽然是字符串,但是类型是ImageFieldFile类型
        return '%s%s%s' % (r'http://127.0.0.1:8000', settings.MEDIA_URL, str(obj.icon))

第二种方法:@property

    gender = serializers.CharField()
    # 第二种方法 在 models.py 的模型表中写 property装饰
    # 自定义序列化字段(插拔式,提倡使用)
    @property
    def gender(self):
        return self.get_sex_display()

View layer

many

1)从数据库中将要序列化给前台的model对象,或是对个model对象查询出来
    user_obj = models.User.objects.get(pk=pk) 或者
    user_obj_list = models.User.objects.all()
2)将对象交给序列化处理,产生序列化对象,如果序列化的是多个数据,要设置many=True
    user_ser = serializers.UserSerializer(user_obj, many=False) 或者
    user_ser = serializers.UserSerializer(user_obj_list, many=True)

Object .data

1)序列化 对象.data 就是可以返回给前台的序列化数据
    return Response(data={
        'status': 0,
        'msg': 0,
        'results': user_ser.data
    })

view.py

class User(APIView):
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            try:
                # 用户对象不能直接作为数据返回给前台
                user_obj = models.User.objects.get(pk=pk)
                # 序列化一下用户对象
                user_ser = serializers.UserSerializer(user_obj)
                # print(user_ser, type(user_ser))
                return Response({
                    'status': 0,
                    'msg': 0,
                    'results': user_ser.data
                })
            except:
                return Response({
                    'status': 2,
                    'msg': '用户不存在',
                })
        else:
            # 用户对象列表(queryset)不能直接作为数据返回给前台
            user_obj_list = models.User.objects.all()
            # 序列化一下用户对象
            user_ser_data = serializers.UserSerializer(user_obj_list, many=True).data
            return Response({
                'status': 0,
                'msg': 0,
                'results': user_ser_data
            })

3. deserialization

1) is provided with the required sequence of optional fields, set validation rules

2) providing a localized field hook function requires additional verification, if the field is not in storage, do not participate in the global hook checksum, the value of the check can be removed

3) provide a global hook function field who have association relationship, if some of the storage fields do not, checksum value may be taken

4) rewriting create a method , by checking the completion of the data storage of the work, the new object obtained

Custom serializer

class UserDeserializer(serializers.Serializer):
    # 1) 哪些字段必须反序列化
    # 2) 字段都有哪些安全校验
    # 3) 哪些字段需要额外提供校验
    # 4) 哪些字段间存在联合校验
    # 注:反序列化字段都是用来入库的,不会出现自定义方法属性,会出现可以设置校验规则的自定义属性(re_pwd)
    name = serializers.CharField(
        max_length=64,
        min_length=3,
        error_messages={
            'max_length': '太长',
            'min_length': '太短'
        }
    )
    pwd = serializers.CharField()
    phone = serializers.CharField(required=False)
    sex = serializers.IntegerField(required=False)

    # 自定义有校验规则的反序列化字段
    re_pwd = serializers.CharField(required=True)

validate_ local field names hook

    # 局部钩子:validate_要校验的字段名(self, 当前要校验字段的值)
    # 校验规则:校验通过返回原值,校验失败,抛出异常
    def validate_name(self, value):
        if 'g' in value.lower():  # 名字中不能出现g
            raise exceptions.ValidationError('名字非法,是个鸡贼!') 
        return value

validate global hook

    # 全局钩子:validate(self, 系统与局部钩子校验通过的所有数据)
    # 校验规则:校验通过返回原值,校验失败,抛出异常
    def validate(self, attrs):
        pwd = attrs.get('pwd')
        re_pwd = attrs.pop('re_pwd')
        if pwd != re_pwd:
            raise exceptions.ValidationError({'pwd&re_pwd': '两次密码不一致'})
        return attrs

Supplementary: validators

Add validators option parameters in the field, also can add validation behavior, such as

def about_django(value):
    if 'django' not in value.lower():
        raise serializers.ValidationError("图书不是关于Django的")

class BookInfoSerializer(serializers.Serializer):
    btitle = serializers.CharField(label='名称', max_length=20, validators=[about_django])

Rewrite create method

    # 要完成新增,需要自己重写 create 方法
    def create(self, validated_data):
        # 尽量在所有校验规则完毕之后,数据可以直接入库
        return models.User.objects.create(**validated_data)

View layer

book_ser = serializers.UserDeserializer(data=request_data) # 数据必须赋值data

ser objects .is_valid () parameters: raise_exception = True

book_ser.is_valid() # 结果为 通过 | 不通过
is_valid() # 方法还可以在验证失败时抛出异常serializers.ValidationError,可以通过传递raise_exception=True参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应

.error & ser ser target objects .validated_data

is_valid() 不通过返回 book_ser.errors 给前台
# 验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。
验证成功,可以通过序列化器对象的validated_data属性获取数据

ser objects .save ()

通过 book_ser.save() # 走得自定义 create 方法 得到新增的对象,再正常返回 

view.py

class User(APIView):
    # 只考虑单增
    def post(self, request, *args, **kwargs):
        # 请求数据
        request_data = request.data
        # 数据是否合法(增加对象需要一个字典数据)
        if not isinstance(request_data, dict) or request_data == {}:
            return Response({
                'status': 1,
                'msg': '数据有误',
            })
        # 数据类型合法,但数据内容不一定合法,需要校验数据,校验(参与反序列化)的数据需要赋值给data
        book_ser = serializers.UserDeserializer(data=request_data)

        # 序列化对象调用is_valid()完成校验,校验失败的失败信息都会被存储在 序列化对象.errors
        if book_ser.is_valid():
            # 校验通过,完成新增
            book_obj = book_ser.save()
            return Response({
                'status': 0,
                'msg': 'ok',
                'results': serializers.UserSerializer(book_obj).data
            })
        else:
            # 校验失败
            return Response({
                'status': 1,
                'msg': book_ser.errors,
            })

save () additional knowledge

1) When serializer for save () save, may additionally transfer data that can be acquired in the create () and update () in parameter validated_data

# request.user 是django中记录当前登录用户的模型对象
serializer.save(owner=request.user)

2) default serialization must pass all required fields, otherwise it will throw an exception verification. But we can use partial parameter to allow some field update

# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)

Guess you like

Origin www.cnblogs.com/lddragon1/p/12113120.html