把正常数据类型入库
在业务逻辑中解耦了对数据的序列化和反序列化
并且 实现了对模型类的增删改查
最终在一般场景下没有其他事情了
序列化 把数据库对象(特定的数据类型)转为通用数据类型
流程 模型类对象---> (序列化器)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>使用参数在序列化器上声明了your,required=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