Django:RestFramework之-------序列化器
8.序列化
- 功能:
- 对请求数据进行验证
- 对Queryset进行序列化
8.1一个简单序列化:
import json
from api import models
from rest_framework import serializers
class RolesSerializer(serializers.Serializer):
title = serializers.CharField()
class RolesView(APIView):
def get(self,request,*args,**kwargs):
"""
#方式一:通过json序列化
roles = models.Role.objects.all().values("id",'title')
roles = list(roles)
ret = json.dumps(roles,ensure_ascii=False)
"""
roles = models.Role.objects.all()
# 实例化序列化器、many=True表示有多条数据
#如果roles为单个对象,序列化前需要设置many=False
ser = RolesSerializer(instance=roles,many=True)
print(ser.data)#[OrderedDict([('title', '医生')]), OrderedDict([('title', '学生')]), OrderedDict([('title', '老师')])]
ret = json.dumps(ser.data, ensure_ascii=False)
return HttpResponse(ret)
结果展示:
1&&序列化之Serializer
class UserInfoSerializer(serializers.Serializer):
num = serializers.IntegerField(source='user_type')
#通过source方法,choice字段可以通过get_字段名_display,显示所需结果
ming = serializers.CharField(source='get_user_type_display')#自动加括号成为可执行。
username = serializers.CharField()
password = serializers.CharField()
#外键,通过source方法,可以通过外键字段.关联表字段 显示所需结果
gp = serializers.CharField(source='group.title')
# 多对多关系需要使用SerializerMethodField,并自定义方法 get_字段。 返回所需结果。
rls = serializers.SerializerMethodField()
def get_rls(self,row):
role_obj_list = row.roles.all()
ret = []
for item in role_obj_list:
ret.append({"id":item.id,"title":item.title})
return ret
class UserInfosView(APIView):
def get(self, request, *args, **kwargs):
user = models.UserInfo.objects.all()
ser = UserInfoSerializer(instance=user,many=True)
ret = json.dumps(ser.data,ensure_ascii=False)
return HttpResponse(ret)
def post(self, request, *args, **kwargs):pass
2.&&ModelSerializer
帮我们找到数据库model设置的那个表,fields的每个字段自动生成serializers.Charfield,serializers.Interfield...
数据库字段与序列化字段对应关系:
#modelSerializer使用
class UserInfoSerializer2(serializers.ModelSerializer):
class Meta:
#表示关联UserInfo那张表
model = models.UserInfo
#表示表中所有字段
fields = "__all__"
class UserInfosView(APIView):
def get(self, request, *args, **kwargs):
user = models.UserInfo.objects.all()
ser = UserInfoSerializer2(instance=user,many=True)
ret = json.dumps(ser.data,ensure_ascii=False)
return HttpResponse(ret)
显示结果:
但显示的结果不太友好,原因user_type,group,roles都显示数字。
更改一下:序列化类
#对于显示数字的字段进行自定义:
class UserInfoSerializer2(serializers.ModelSerializer):
#序列化choice字段
num = serializers.IntegerField(source='user_type')
#序列化多对多关系的
rls = serializers.SerializerMethodField()
#序列化外键外键
gp = serializers.CharField(source='group.title')
def get_rls(self,row):
role_obj_list = row.roles.all()
ret = []
for item in role_obj_list:
ret.append({"id":item.id,"title":item.title})
return ret
class Meta:
model = models.UserInfo
fields = ["id","username","password","num","rls","gp"]
- 显示效果:
8.2序列化小总结:
*写序列化类可继承:
1.serializers.Serializer
2.serializers.ModelSerializer
*字段:
#序列化choice字段
num = serializers.IntegerField(source='user_type')
#序列化多对多关系的
rls = serializers.SerializerMethodField()
#序列化外键外键
gp = serializers.CharField(source='group.title')
8.3拓展:
#自定义字段
class MyField(serializers.CharField):
def to_representation(self, value):
#对字段value进行处理,返回处理后的new_value
new_value = value + "ABCDEFG"
return new_value
class UserInfoSerializer2(serializers.ModelSerializer):
...
#MyField为自己定义字段, source用于连接数据库中字段
myfiled = MyField(source="username")
class Meta:
model = models.UserInfo
fields = ["id","username","password","num","rls","gp","myfiled"]
显示效果:
depth 使用让代码更加简洁。表示向里渗透层数。
class UserInfoSerializer3(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
depth = 1#官方文档建议0~10,自己建议3层左右
#depth使用要节制,层数设置越多,响应速率越慢
显示效果:
8.4hypermedialink 生成链接
- 将group生成url路由:
#1.路由,首先在路由定义group路由
url(r'^(?P<version>[v1|v2]+)/group/(?P<pk>\d+)/$', views.GroupView.as_view(),name='gp'),
#2.定义完整视图类,以及用于序列化UserGroup的序列化类。
class GroupSerializer(serializers.ModelSerializer):
#UserGroup表中序列化器
class Meta:
model = models.UserGroup
fields = "__all__"
class GroupView(APIView):
def get(self,request,pk,*args,**kwargs):
#获取当前pk,拿当前pk值查询数据库获取对象
print(pk)
obj = models.UserGroup.objects.filter(pk=pk).first()
#序列化器序列化对象
ser = GroupSerializer(instance=obj,many=False)
#返回结果
ret = json.dumps(ser.data,ensure_ascii=False)
return HttpResponse(ret)
#3.更改用于UserInfosView视图类的序列化类
class UserInfoSerializer4(serializers.ModelSerializer):
#根据view_name根据所赋值,反向解析路由中的url
#group字段序列化完为当前group所得id对应的url
#lookup_url_kwarg 传入的url路由中的设置参数
#lookup_field 为当前表关联UserGroup表的字段
group = serializers.HyperlinkedIdentityField(view_name="gp",lookup_field="group_id",lookup_url_kwarg="pk")
class Meta:
model = models.UserInfo
fields = ["id","username","password","group"]
depth = 0
#4.UserInfosView使用序列化器
def get(self, request, *args, **kwargs):
ser = UserInfoSerializer4(instance=user,many=True,context={"request":request})
#当访问UserInfosView视图类对应路由
显示效果:
8.5序列化器源码解析
1.当视图类进行实例化序列化类做了如下操作:
#ModelSerializer 继承Serializer 继承BaseSerializer
#在BaseSerializer执行__new__方法,用于判断many是为True还是False:
def __new__(cls, *args, **kwargs):
if kwargs.pop('many', False):
#many = True, 对QuerySet进行处理
return cls.many_init(*args, **kwargs)
#many = False 对对象进行处理, 然后执行初始化方法__init__
return super().__new__(cls, *args, **kwargs)
#当many=True:为QuerySet对象,用ListSerializer进行处理
#当many=False:为单个对象,用Serializer进行处理
2.当实例化序列类调用data方法:
ser.data 执行:to_representation
def to_representation(self, instance):
ret = OrderedDict()
fields = self._readable_fields
for field in fields:
try:
#遍历循环对象, 该对象可以:对象.字段 eg:对象.username
attribute = field.get_attribute(instance)
except SkipField:
continue
3.执行get_attribute方法:
def get_attribute(self, instance):
try:
#instance为对象
#source_attrs:为一个列表 [group.title...] / get_user_type_display /roles.all
return get_attribute(instance, self.source_attrs)
4.执行get_attribute:
def get_attribute(instance, attrs):
#循环所有字段,将字段赋值给instance,
print("--->",attrs)#attrs为一个列表,遍历列表取字段。[id,]
print(instance)#istance 是UserInfo object对象
for attr in attrs:
try:
if isinstance(instance, Mapping):
instance = instance[attr]
else:
instance = getattr(instance, attr)
except ObjectDoesNotExist:
return None
#如果该对象是可执行的如: get_user_type_display 类型。那就加括号执行
if is_simple_callable(instance):
try:
instance = instance()
print("*****",instance)#1
except (AttributeError, KeyError) as exc:
# If we raised an Attribute or KeyError here it'd get treated
# as an omitted field in `Field.get_attribute()`. Instead we
# raise a ValueError to ensure the exception is not masked.
raise ValueError('Exception raised in callable attribute "{}"; original exception was: {}'.format(attr, exc))
return instance
"""
---> ['id']
UserInfo object
***** 1
---> ['username']
UserInfo object
***** aaa
---> ['password']
UserInfo object
***** 123
---> []
UserInfo object
---> ['id']
UserInfo object
***** 2
---> ['username']
UserInfo object
***** bbb
---> ['password']
UserInfo object
***** 123
---> []
UserInfo object
"""
8.6序列化器之数据校验
- 内置校验方法 和 自定义校验 和 钩子函数
class xxValidator(object):
"""自定义校验器"""
def __init__(self,base):
self.base = base
def __call__(self,value):
if not value.startswith(self.base):
msg = "标题必须以%s为开头"%self.base
raise serializers.ValidationError(msg)
class UserGroupSerializer(serializers.Serializer):
#定义title的error_messages错误信息显示,post为空时候会显示标题不能为空
#通过validators里面放置处理自定义校验器的方法。
title = serializers.CharField(error_messages={"required":"标题不能为空"},validators=[xxValidator("老男人"),])
#局部钩子,触发异常
def validate_title(self,value):
from rest_framework import exceptions
raise exceptions.ValidationError("就是想触发异常")
return value
class UserGroupView(APIView):
def post(self,request,*args,**kwargs):
print(request.data)
ser = UserGroupSerializer(data=request.data)
if ser.is_valid():
print(ser.validated_data)#为一个OrderedDict对象,打印提交数据
else:
print(ser.errors)#打印错误数据。如果提交空表单数据 会打印{'title': [ErrorDetail(string='标题不能为空', code='required')]}
return HttpResponse("提交数据")
8.7.序列化之源码深度解析
源码小技巧,当源码中有类实例化,一般将数据进行封装,封装成一个对象。一大堆赋值过程。有
__new__
方法会先执行此方法,用于构造对象。1.实例化一般是将数据进行封装到对象:
__new__
,__init__
- 当实例化对象many=True,会执行ListSerializer对象构造方法
- 当实例化对象many=False,会执行自身序列化器对象构造方法
2.调用对象data属性:
执行ListSerializer中to_representation方法。 对于数据展示,一直调用ListSerializer
class ListSerializer
def to_representation(self, data): iterable = data.all() if isinstance(data, models.Manager) else data return [
#循环每一个数据库的对象,再根据每一个对象,去调用它的每个字段的to_representation来做显示
self.child.to_representation(item) for item in iterable
]执行自己data,调用to_representation
#当执行自己Serializer
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
@property
def data(self):
#去父类执行data函数(父类BaseSerializer)
ret = super().data
#封装有序字典
return ReturnDict(ret, serializer=self)
#--------------------------------------------------------------------------
class BaseSerializer:
@property
def data(self):
if hasattr(self, 'initial_data') and not hasattr(self, '_validated_data'):
msg = (
'When a serializer is passed a `data` keyword argument you '
'must call `.is_valid()` before attempting to access the '
'serialized `.data` representation.\n'
'You should either call `.is_valid()` first, '
'or access `.initial_data` instead.'
)
raise AssertionError(msg) if not hasattr(self, '_data'):
if self.instance is not None and not getattr(self, '_errors', None):
self._data = self.to_representation(self.instance)
elif hasattr(self, '_validated_data') and not getattr(self, '_errors', None):
#执行to_representation,自己类中定义了此方法,去自己类中执行
self._data = self.to_representation(self.validated_data)
else:
self._data = self.get_initial()
return self._data
#--------------------------------------------------------------------------
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
def to_representation(self, instance):
ret = OrderedDict()
fields = self._readable_fields
#遍历循环每个field字段。field为我们序列化器写的每个字段。
#序列化器中定义每个字段帮助我们去数据库里面把数据库字段拿取过来,通过Charfield,Interfield等类进行展示
for field in fields:
try:
#去数据库中获取指定字段对应值
#比如:
#当filed为id, 此时attribute=1
#当filed为pwd, 此时attribute=123
#如果设置特殊字段如:HyperlinkedIdentityField,它只会把当前字段对象取出来:obj
attribute = field.get_attribute(instance)
except SkipField:
continue
check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute
if check_for_none is None:
ret[field.field_name] = None
else:
#相当于:
"""
{
id:1, CharField
pwd:123, CharField
group:obj, HyperlinkedIdentityField
}
"""
#通过每个字段类型再执行to_representation,
#因为有些字段一次无法拿到对应的值,所以,再通过各个字段的方法,如
#id:1 Charfield
#会执行field.to_representation(attribute) === Charfield.to_representation(1)
#Charfield中to_representation方法return six.text_type(value) === return str(value) #而HyperlinkedIdentityField 执行to_representation,用反射方法去数据库找lookup_filed设置的字段,去数据库拿值,然后根据咱们之前设置好的look_url_kwargs的值(此值为url路由上设置动态参数名字)。然后通过这2个值通过reverse反向生成url.
ret[field.field_name] = field.to_representation(attribute) return ret
- 序列化器之校验源码
#is_valid()
def is_valid(self, raise_exception=False):
...
if not hasattr(self, '_validated_data'):
try:
#执行run_validation方法,此时注意要执行自己类的run_validation,为Serializer
self._validated_data = self.run_validation(self.initial_data)
except ValidationError as exc:
self._validated_data = {}
self._errors = exc.detail
else:
self._errors = {} if self._errors and raise_exception:
raise ValidationError(self.errors) return not bool(self._errors)
#--------------------------------------------------------------------
def run_validation(self, data=empty):
(is_empty_value, data) = self.validate_empty_values(data)
if is_empty_value:
return data
#执行to_internal_value方法
value = self.to_internal_value(data)
try:
self.run_validators(value)
value = self.validate(value)
assert value is not None, '.validate() should return the validated data'
except (ValidationError, DjangoValidationError) as exc:
raise ValidationError(detail=as_serializer_error(exc)) return value
#----------------------------------------------------------------------
def to_internal_value(self, data):
if not isinstance(data, Mapping):
message = self.error_messages['invalid'].format(
datatype=type(data).__name__
)
raise ValidationError({
api_settings.NON_FIELD_ERRORS_KEY: [message]
}, code='invalid') ret = OrderedDict()
errors = OrderedDict()
fields = self._writable_fields for field in fields:
validate_method = getattr(self, 'validate_' + field.field_name, None)
primitive_value = field.get_value(data)
try:
#执行字段本身内置方法。
validated_value = field.run_validation(primitive_value)
if validate_method is not None:
#执行验证的钩子方法
validated_value = validate_method(validated_value)
except ValidationError as exc:
errors[field.field_name] = exc.detail
except DjangoValidationError as exc:
errors[field.field_name] = get_error_detail(exc)
except SkipField:
pass
else:
set_value(ret, field.source_attrs, validated_value) if errors:
raise ValidationError(errors) return ret
Django:RestFramework之-------序列化器的更多相关文章
- python Django rest-framework 创建序列化工程步骤
11创建项目 2创建应用 3stting添加应用(apps)-添加制定数据库-修改显示汉字(zh-hans)-上海时区(Asia/Shanghai) 4主路由添加子路由 5应用里创建子路由 6创建数据 ...
- django rest-framework 1.序列化 二
在上一节说了Serializers的使用类似Django的From,在Django中有From也有ModelFrom,Serializers也是有个ModelSerializers,下面在讲讲rest ...
- Django REST Framework序列化器
Django序列化和json模块的序列化 从数据库中取出数据后,虽然不能直接将queryset和model对象以及datetime类型序列化,但都可以将其转化成可以序列化的类型,再序列化. 功能需求都 ...
- Django 学习之Django Rest Framework_序列化器_Serializer
作用: 1.序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串. 2.反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型. 3 ...
- RestFramework之序列化器源码解析
一.源码解析之序列化: 1.当视图类进行实例化序列化类做了如下操作: #ModelSerializer继承Serializer再继承BaseSerializer(此类定义实例化方法) #在BaseSe ...
- django rest-framework 1.序列化 一
上图为项目完整的目录结构 一.入门 需要先安装需要使用到包 pip install django pip install djangorestframework 先来创建一个新项目 django-ad ...
- Django:RestFramework之-------解析器
7.解析器 依靠Content-Type对用户的请求体中的数据进行解析. 7.1django中的解析器 前戏:django中的request.POST/request.body request.POS ...
- Django:RestFramework之-------渲染器
12.渲染器 from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer,AdminRenderer class Te ...
- Django rest-framework框架-解析器
解析器: 开始: django: request.POST/ request.body 满足一下两个要求POST中才有值 1. 如果请求头中的 Content-Type: application/x- ...
随机推荐
- Python3 if 变量variable SQL where 语句拼接
最近在写python3的项目,在实际中运用到了根据 if 判断变量variable ,然后去拼接where子句.但是在百度.BING搜索中未找到合适的答案,这是自己想出来的典型php写法,这里做一下记 ...
- robotframework-selenium2library各个版本
https://github.com/robotframework/Selenium2Library/downloads
- nginx访问限制
nginx的访问控制 1.http_access_module 基于ip的访问控制 允许的访问配置 不允许的访问配置 server { listen 80; server_name localho ...
- LeetCode 825. Friends Of Appropriate Ages
原题链接在这里:https://leetcode.com/problems/friends-of-appropriate-ages/ 题目: Some people will make friend ...
- Spring Data学习中心
Spring Data 概览 Spring Data的使命是为数据访问提供熟悉且一致的基于Spring的编程模型,同时仍保留底层数据存储的特殊特性. 它使数据访问技术,关系数据库和非关系数据库,map ...
- ORM常用的13个方法
介绍一个可以以py脚本方式运行ORM操作的方法: 可在项目内新建个py文件,复制项目内manage.py文件中的以下代码: if __name__ == "__main__": o ...
- Django学习----js传参给view.py
需求: 散点图中每选择一个点,获取到id之后传给view.py,根据这个id进行sql语句的查询. 问题: 要求实时查询 解决办法: ajax查询 js页面 .on("mousedown&q ...
- jquery swipper插件的一些弊端
jquery swipper插件的一些弊端touch触摸机制是swipper的 阻止click冒泡.拖动Swiper时阻止click事件.下面这个方法或许可以解决触摸机制的问题 <pre> ...
- vue父子(父传子)传值
vue2.0中,实现父子组件间的传值,需要依靠一个props的属性,作为变量接收的对象. 注:vue.js文件引用的是本地的js文件,拷贝本机运行时,可以使用cnd替换. https://www.bo ...
- [转帖]美团在Redis上踩过的一些坑-5.redis cluster遇到的一些问题
美团在Redis上踩过的一些坑-5.redis cluster遇到的一些问题 博客分类: redis 运维 redis clustercluster-node-timeoutfailover 转载请 ...