DRF 序列化器


把正常数据类型入库

在业务逻辑中解耦了对数据的序列化和反序列化

并且 实现了对模型类的增删改查

最终在一般场景下没有其他事情了

序列化 把数据库对象(特定的数据类型)转为通用数据类型

流程 模型类对象---> (序列化器)python 字典-------> (渲染器)json 字符串

实现流程代码

from datetime import datetime

# 定义一个python 类 (特殊数据类型)
class Comment:
    def __init__(self, email, content, created=None):
        self.email = email
        self.content = content
        self.created = created or datetime.now()

comment = Comment(email='leila@example.com', content='foo bar')

from rest_framework import serializers

# 定义一个序列化器 (转化特殊数据类型)
class CommentSerializer(serializers.Serializer):
    email = serializers.EmailField()
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()

 # 数据提取--转化 常见的python 字典
serializer = CommentSerializer(comment)
serializer.data
# {'email': 'leila@example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}

from rest_framework.renderers import JSONRenderer
# drf渲染器 将python字典 转换为json 串
json = JSONRenderer().render(serializer.data)
json
# b'{"email":"leila@example.com","content":"foo bar","created":"2016-01-27T15:17:10.375877"}'

反序列化是相反的 常用数据类型转换为 特定数据类型

流程 请求---->(解析器)解析json 字符串 --> (序列化器)转成字典 在转------->模型类对象-

import io
from rest_framework.parsers import JSONParser

stream = io.BytesIO(json) # BytesIO实现了在内存中读写bytes模拟网络通信
data = JSONParser().parse(stream)


serializer = CommentSerializer(data=data)
serializer.is_valid()
# True
serializer.validated_data
# {'content': 'foo bar', 'email': 'leila@example.com', 'created': datetime.datetime(2012, 08, 22, 16, 20, 09, 822243)}


# 转化为特殊数据类型 类对象或模型对象
class CommentSerializer(serializers.Serializer):
    email = serializers.EmailField()
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()

    def create(self, validated_data):
        return Comment(**validated_data)
       # Comment.objects.create(**validated_data) # 模型类

    def update(self, instance, validated_data):
        instance.email = validated_data.get('email', instance.email)
        instance.content = validated_data.get('content', instance.content)
        instance.created = validated_data.get('created', instance.created)
        # instance.save() 模型类
        return instance

# 现在,在对数据进行反序列化时,我们可以.save()基于已验证的数据调用以返回对象实例。 
# 得到了特殊数据类型
 comment = serializer.save()    

    # 再进行一次序列化确认下
 # .save() will create a new instance.
serializer = CommentSerializer(data=data)

# .save() will update the existing `comment` instance.
serializer = CommentSerializer(comment, data=data)


# 并且在返回实例的时候可以给它注入一些新的属性
serializer.save(owner=request.user)


反序列化数据时您始终需要先调用is_valid()然后再尝试访问经过验证的数据或保存对象实例如果发生任何验证错误则该.errors属性将包含代表所得错误消息的字典例如

serializer = CommentSerializer(data={'email': 'foobar', 'content': 'baz'})
serializer.is_valid()
# False
serializer.errors
# {'email': ['Enter a valid e-mail address.'], 'created': ['This field is required.']}


#  带异常的校验
serializer.is_valid(raise_exception=True) 



# 添加自定义字段校验

from rest_framework import serializers

class BlogPostSerializer(serializers.Serializer):
    title = serializers.CharField(max_length=100)
    content = serializers.CharField()

    def validate_title(self, value):
        """
        Check that the blog post is about Django.
        """
        if 'django' not in value.lower():
            raise serializers.ValidationError("Blog post is not about Django")
        return value
  注意如果<field_name>使用参数在序列化器上声明了yourrequired=False那么如果不包含该字段则不会执行此验证步骤

# 对整个对象校验
from rest_framework import serializers

class EventSerializer(serializers.Serializer):
    description = serializers.CharField(max_length=100)
    start = serializers.DateTimeField()
    finish = serializers.DateTimeField()

    def validate(self, data):
        """
        Check that start is before finish.
        """
        if data['start'] > data['finish']:
            raise serializers.ValidationError("finish must occur after start")
        return data

# 进一步封装成验证器
def multiple_of_ten(value):
    if value % 10 != 0:
        raise serializers.ValidationError('Not a multiple of ten')

class GameRecord(serializers.Serializer):
    score = IntegerField(validators=[multiple_of_ten])

 # 对象级别验证器
 class EventSerializer(serializers.Serializer):
    name = serializers.CharField()
    room_number = serializers.IntegerField(choices=[101, 102, 103, 201])
    date = serializers.DateField()

    class Meta:
        # Each room only has one event per day.
        validators = [
            UniqueTogetherValidator(
                queryset=Event.objects.all(),
                fields=['room_number', 'date']
            )
        ]
        # 部分更新
    serializer = CommentSerializer(comment, data={'content': 'foo bar'}, partial=True)



 # 序列化器嵌套
class UserSerializer(serializers.Serializer):
    email = serializers.EmailField()
    username = serializers.CharField(max_length=100)

class CommentSerializer(serializers.Serializer):
    user = UserSerializer()
     user = UserSerializer(required=False) #  非必串
    edits = EditItemSerializer(many=True)  # A nested list of 'edit' items. 可迭代对象
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()


 # 当处理支持反序列化数据的嵌套表示形式时,嵌套对象的任何错误都将嵌套在嵌套对象的字段名称下。
    serializer = CommentSerializer(data={'user': {'email': 'foobar', 'username': 'doe'}, 'content': 'baz'})
serializer.is_valid()
# False
serializer.errors
# {'user': {'email': ['Enter a valid e-mail address.']}, 'created': ['This field is required.']}

# 写入的时候提出多余数据 一个借口写入两个关联表的时候
class UserSerializer(serializers.ModelSerializer):
    profile = ProfileSerializer()

    class Meta:
        model = User
        fields = ['username', 'email', 'profile']

    def create(self, validated_data):
        profile_data = validated_data.pop('profile')
        user = User.objects.create(**validated_data)
        Profile.objects.create(user=user, **profile_data)
        return user

  # 嵌套更新
    def update(self, instance, validated_data):
        profile_data = validated_data.pop('profile')
        # Unless the application properly enforces that this field is
        # always set, the following could raise a `DoesNotExist`, which
        # would need to be handled.
        profile = instance.profile

        instance.username = validated_data.get('username', instance.username)
        instance.email = validated_data.get('email', instance.email)
        instance.save()

        profile.is_premium_member = profile_data.get(
            'is_premium_member',
            profile.is_premium_member
        )
        profile.has_support_contract = profile_data.get(
            'has_support_contract',
            profile.has_support_contract
         )
        profile.save()

        return instance


 # 这样是复杂的

# 推荐方案是通过manager 构建模型管理器
class UserManager(models.Manager):
    ...

    def create(self, username, email, is_premium_member=False, has_support_contract=False):
        user = User(username=username, email=email)
        user.save()
        profile = Profile(
            user=user,
            is_premium_member=is_premium_member,
            has_support_contract=has_support_contract
        )
        profile.save()
        return user
  # 更新manage 之后的写法
 def create(self, validated_data):
    return User.objects.create(
        username=validated_data['username'],
        email=validated_data['email'],
        is_premium_member=validated_data['profile']['is_premium_member'],
        has_support_contract=validated_data['profile']['has_support_contract']
    )


# 对对象处理
queryset = Book.objects.all()
serializer = BookSerializer(queryset, many=True)
serializer.data
# [
#     {'id': 0, 'title': 'The electric kool-aid acid test', 'author': 'Tom Wolfe'},
#     {'id': 1, 'title': 'If this is a man', 'author': 'Primo Levi'},
#     {'id': 2, 'title': 'The wind-up bird chronicle', 'author': 'Haruki Murakami'}
# ]
# 反序列化支持批量创建但没有批量更新


# 上下文序列化
serializer = AccountSerializer(account, context={'request': request})
serializer.data
# {'id': 6, 'owner': 'denvercoder9', 'created': datetime.datetime(2013, 2, 12, 09, 44, 56, 678870), 'details': 'http://example.com/accounts/6/details'}

ModelSerializer

ModelSerializer
它将根据模型自动为您生成一组字段
它将自动为序列化器生成验证器例如unique_together验证器
它包括简单的默认实现.create().update()

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ['id', 'account_name', 'users', 'created']
       # b默认情况下,该类上的所有模型字段都将映射到 相应 序列化器字段。
   # 查看生成实际代码
  >>> from myapp.serializers import AccountSerializer
>>> serializer = AccountSerializer()
>>> print(repr(serializer))
AccountSerializer():
    id = IntegerField(label='ID', read_only=True)
    name = CharField(allow_blank=True, max_length=100, required=False)
    owner = PrimaryKeyRelatedField(queryset=User.objects.all())

  # 指定字段
class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ['id', 'account_name', 'users', 'created'] # 包含
        fields = '__all__'# 全选
        exclude = ['users'] # 不包含

       # 嵌套方式1
    class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ['id', 'account_name', 'users', 'created']
        depth = 1
        # 嵌套方式2
       class AccountSerializer(serializers.ModelSerializer):
    url = serializers.CharField(source='get_absolute_url', read_only=True)
    groups = serializers.PrimaryKeyRelatedField(many=True)

    class Meta:
        model = Account
        # 指定只读字段
     class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ['id', 'account_name', 'users', 'created']
        read_only_fields = ['account_name']
      # 默认情况下,已editable=False设置的模型字段和AutoField字段将设置为只读,并且不需要将其添加到该read_only_fields选项中。
    # 
    user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())


    # 附加参数
    class CreateUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['email', 'username', 'password']
        extra_kwargs = {'password': {'write_only': True}}

    def create(self, validated_data):
        user = User(
            email=validated_data['email'],
            username=validated_data['username']
        )
        user.set_password(validated_data['password'])
        user.save()
        return user


# 实现批量修改
class BookListSerializer(serializers.ListSerializer):
    def create(self, validated_data):
        books = [Book(**item) for item in validated_data]
        return Book.objects.bulk_create(books)

class BookSerializer(serializers.Serializer):
    ...
    class Meta:
        list_serializer_class = BookListSerializer