目录
ModelSerializer与常规Serializer的不同之处
ModelSerializer与常规Serializer的不同之处
- 基于模型类自动生成一系列字段
- 包含默认的create()和update()的实现
- 基于模型类自动为Serializer生成validators,比如unique_together
序列化
serializers.py
class BookModelSerializer(ModelSerializer):
# 自定义连表深度 - 子序列化方式
publish = PublishModelSerializer()
class Meta:
# 序列化类关联的
model = models.Book
# 参与序列化的字段
fields = ('name', 'price', 'author_list', 'publish_name', 'publish')
# 仅了解
# 所有字段
# fields = '__all__'
# exclude排除字段
# exclude = ('id', 'is_delete', 'create_time')
# 自动深度连表
# depth = 1
model.py中Book类设置publish_name和author_list属性方法
# 自定义字段:可以连表,可以完成数据相关的逻辑
# 序列化插拔式属性 - 完成自定义字段名完成连表查询
@property
def publish_name(self):
return self.publish.name
@property
def author_list(self):
return self.author.values('name', 'age').all()
views.py
class Book(APIView):
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
# 单查
if pk:
try:
book_obj = models.Book.objects.get(pk=pk, is_delete=False)
book_data = serializers.BookModelSerializer(book_obj).data
return Response({
'status': 1,
'msg': 'ok',
'result': book_data
})
except:
return Response({
'status': 1,
'msg': '书籍不存在'
})
# 群查
else:
book_query = models.Book.objects.filter(is_delete=False).all()
book_data = serializers.BookModelSerializer(book_query, many=True).data
return Response({
'status': 1,
'msg': 'ok',
'result': book_data
})
应用下路由 urls.py
urlpatterns = [
url(r'^books/$', views.Book.as_view()),
url(r'^books/(?P<pk>.*)/$', views.Book.as_view()),
]
反序列化
serializers.py
- 在设置fields时, 没有默认值的字段都必须设置反序列化保存到数据库中
- 使用extra_kwargs来设置系统校验规则
- 设置局部钩子和全局钩子
- 注意:ModelSerializer类已经帮我们实现了create与update方法,不需要写create就能创建
class BookModelDeserializer(ModelSerializer):
class Meta:
model = models.Book
fields = ('name', 'price', 'authors') #没有默认值的字段必须序列化,为其传值
# extra_kwargs 用来完成反序列化字段的 系统校验规则
extra_kwargs = {
'name': {
'required': True,
'min_length': 10,
'error_message': {
'required': '必填项',
'min_length': '太短'
}
}
}
# 局部钩子校验单个字段 validate_字段名
def validated_name(self, value):
# 书名不能包含 g 字符
if 'g' in value.lower():
raise ValidationError('该g书不能出版')
return value
# 全局钩子
def validate(self, attrs):
publish = attrs.get('publish') #publish如果是外键字段,这个就是publish对象
name = attrs.get('name')
if models.Book.objects.filter(name=name, publish=publish):
raise ValidationError({'book': '该书已存在'})
return attrs
views.py
- POST请求通过request.data拿到数据包
- 传给反序列化,通过data=request_data传入需要反序列化的数据
- is_valid判断校验是否合格,raise_exception=True必须要写的
- 通过.save()保存到数据库中
def post(self, request, *args, **kwargs):
request_data = request.data
book_ser = serializers.BookModelDeserializer(data=request_data)
# 当校验失败,马上终止当前视图方法,抛异常返回给前台
book_ser.is_valid(raise_exception=True) #检验是否合格 raise_exception=True必填的
book_obj = book_ser.save() #保存得到一个对象
return Response({
'status': 0,
'msg': 'ok',
'results': serializers.BookModelDeserializer(book_obj).data
})
uls.py
- 在postman中访问路径时最后必须带上/,post请求方式只有json格式能一个字段提交多个值,放在列表或者元祖中,其余两个只能传递单个值
urlpatterns = [
url(r'^books/$', views.Book.as_view()),
url(r'^books/(?P<pk>.*)/$', views.Book.as_view()),
]
序列化和反序列化整合(重点)
serializers.py
- fields中设置所有序列化与反序列化字段
- extra_kwargs划分只序列化或只反序列化字段
- write_only:只反序列化
- read_only:只序列化
- 自定义字段默认只序列化(read_only)
- 如果字段没设置write_only或者read_only,那么该字段可以序列化和反序列化
- 设置反序列化所需的 系统、局部钩子、全局钩子等校验规则
class V2BookModelSerializer(ModelSerializer):
class Meta:
# 序列化类关联的
model = models.Book
# 参与序列化的字段
fields = ('name', 'price', 'img', 'author_list', 'publish_name', 'publish', 'authors')
extra_kwags = {
'name': {
'required': True,
'min_length': 10,
'error_message': {
'required': '必填项',
'min_length': '太短'
}
},
'publish': {
'write_only': True
},
'authors': {
'write_only': True
},
'img': {
'read_only': True
},
'author_list': {
'read_only': True
},
'publish_name': {
'read_only': True
},
}
# 局部钩子校验单个字段 validate_字段名
def validated_name(self, value):
# 书名不能包含 g 字符
if 'g' in value.lower():
raise ValidationError('该g书不能出版')
return value
# 全局钩子
def validate(self, attrs):
publish = attrs.get('publish') # publish如果是外键字段,这个就是publish对象
name = attrs.get('name')
if models.Book.objects.filter(name=name, publish=publish):
raise ValidationError({'book': '该书已存在'})
return attrs
views.py
- 序列化数据最后必须要.data (因为要传给前端)
- 反序列化通过data传参,序列化通过instance传参(当只传一个参数时,默认是instance的参数)
- 反序列化与序列化都能使用many=True,序列化和反序列化数据只要被[]嵌套都要写many=True
class V2Book(APIView):
# 单查:有pk
# 群查:无pk
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
if pk:
try:
book_obj = models.Book.objects.get(pk=pk, is_delete=False)
book_data = serializers.V2BookModelSerializer(book_obj).data
return Response({
'status': 1,
'msg': 'ok',
'result': book_data
})
except:
return Response({
'status': 1,
'msg': '书籍不存在'
})
else:
book_query = models.Book.objects.filter(is_delete=False).all()
book_data = serializers.V2BookModelSerializer(book_query, many=True).data
return Response({
'status': 1,
'msg': 'ok',
'result': book_data
})
# 单增:传的数据是与model对应的字典
# 群增:穿的数据是 装多个model对应字典的 列表
def post(self, request, *args, **kwargs):
request_data = request.data
if isinstance(request_data, dict):
many = False
elif isinstance(request_data, list):
many = True
else:
return Response({
'status': 1,
'msg': '数据有误',
})
book_ser = serializers.V2BookModelSerializer(data=request_data, many=many)
# 当校验失败,马上种植当前视图方法,抛异常返回给前台
book_ser.is_valid(raise_exception=True) #启动序列化校验规则(系统内容=>局部钩子=>全局钩子)
book_obj = book_ser.save()
return Response({
'status': 0,
'msg': 'ok',
'results': serializers.V2BookModelSerializer(book_obj, many=many).data
})
# 单删:有pk
# 群删:有pks
def delete(self, request, *args, **kwargs):
pk = kwargs.get('pk')
if pk:
pks = [pk]
else:
pks = request.data.get('pks')
if models.Book.objects.filter(pk__in=pks, is_delete=False).update(is_delete=True):
return Response({
'status': 0,
'msg': '删除成功'
})
return Response({
'status': 1,
'msg': '删除失败'
})
urls.py
urlpatterns = [
url(r'^v2/books/$', views.V2Book.as_view()),
url(r'^v2/books/(?P<pk>.*)/$', views.V2Book.as_view()),
]
序列化的四个重要参数
instance、data、many、partial
序列化情况:
- 如果没有data参数,只有instance,那么就不存在反序列化校验一说,只有序列化对象instance
反序列化情况:
- 如果有data,没有instance,那么需要进行校验data,然后将data进行反序列化,得到validated_data后的data,此时再通过序列化对象获取data,这个data和初始化提供的data不一样,这个序列化validated_data后的data,比起初始化data,可能减少了无效的字段(序列化没有定义的字段)
修改情况:
- 如果又提供了instance又提供了data,那么只要又data或者部分data,那么data都要进行验证才能进行下面的save等操作,如果不经过is_valid过程,那么后面的获取序列化数据或者反序列化数据都会无效。
ListSerializer使用情况:
- many参数将直接影响序列化类的类型,如果是many=False,那么直接使用当前序列化类。如果many=True,将实例化一个ListSerializer类来序列化或者反序列化类。