rest framework 学习 序列化
序列化功能:对请求数据进行验证和对Queryset进行序列化
Queryset进行序列化:
1 序列化之Serializer


1 class UserInfoSerializer(serializers.Serializer):
2 num = serializers.IntegerField(source='user_type')
3 #通过source方法,choice字段可以通过get_字段名_display,显示所需结果
4 ming = serializers.CharField(source='get_user_type_display')#自动加括号成为可执行。
5 username = serializers.CharField()
6 password = serializers.CharField()
7 #外键,通过source方法,可以通过外键字段.关联表字段 显示所需结果
8 gp = serializers.CharField(source='group.title')
9 # 多对多关系需要使用SerializerMethodField,并自定义方法 get_字段。 返回所需结果。
10 rls = serializers.SerializerMethodField()
11 def get_rls(self,row):
12 role_obj_list = row.roles.all()
13 ret = []
14 for item in role_obj_list:
15 ret.append({"id":item.id,"title":item.title})
16 return ret
17
18 class UserInfosView(APIView):
19 def get(self, request, *args, **kwargs):
20 user = models.UserInfo.objects.all()
21 ser = UserInfoSerializer(instance=user,many=True)
22 ret = json.dumps(ser.data,ensure_ascii=False)
23 return HttpResponse(ret)
24 def post(self, request, *args, **kwargs):pass
2.ModelSerializer


1 #对于显示数字的字段进行自定义:
2 class UserInfoSerializer2(serializers.ModelSerializer):
3 #序列化choice字段
4 num = serializers.IntegerField(source='user_type')
5 #序列化多对多关系的
6 rls = serializers.SerializerMethodField()
7 #序列化外键外键
8 gp = serializers.CharField(source='group.title')
9 def get_rls(self,row):
10 role_obj_list = row.roles.all()
11 ret = []
12 for item in role_obj_list:
13 ret.append({"id":item.id,"title":item.title})
14 return ret
15 class Meta:
16 model = models.UserInfo
17 fields = ["id","username","password","num","rls","gp"]
3 自定义字段


1 #自定义字段
2 class MyField(serializers.CharField):
3 def to_representation(self, value):
4 #对字段value进行处理,返回处理后的new_value
5 new_value = value + "ABCDEFG"
6 return new_value
7 class UserInfoSerializer2(serializers.ModelSerializer):
8 ...
9 #MyField为自己定义字段, source用于连接数据库中字段
10 myfiled = MyField(source="username")
11 class Meta:
12 model = models.UserInfo
13 fields = ["id","username","password","num","rls","gp","myfiled"]
4 depth使用
1 class UserInfoSerializer3(serializers.ModelSerializer):
2 class Meta:
3 model = models.UserInfo
4 fields = "__all__"
5 depth = 1#官方文档建议0~10,自己建议3层左右
6 #depth使用要节制,层数设置越多,响应速率越慢
5hypermedialink 生成链接


1 #1.路由,首先在路由定义group路由
2 url(r'^(?P<version>[v1|v2]+)/group/(?P<pk>\d+)/$', views.GroupView.as_view(),name='gp'),
3
4
5 #2.定义完整视图类,以及用于序列化UserGroup的序列化类。
6 class GroupSerializer(serializers.ModelSerializer):
7 #UserGroup表中序列化器
8 class Meta:
9 model = models.UserGroup
10 fields = "__all__"
11 class GroupView(APIView):
12 def get(self,request,pk,*args,**kwargs):
13 #获取当前pk,拿当前pk值查询数据库获取对象
14 print(pk)
15 obj = models.UserGroup.objects.filter(pk=pk).first()
16 #序列化器序列化对象
17 ser = GroupSerializer(instance=obj,many=False)
18 #返回结果
19 ret = json.dumps(ser.data,ensure_ascii=False)
20 return HttpResponse(ret)
21 #3.更改用于UserInfosView视图类的序列化类
22 class UserInfoSerializer4(serializers.ModelSerializer):
23 #根据view_name根据所赋值,反向解析路由中的url
24 #group字段序列化完为当前group所得id对应的url
25 #lookup_url_kwarg 传入的url路由中的设置参数
26 #lookup_field 为当前表关联UserGroup表的字段
27 group = serializers.HyperlinkedIdentityField(view_name="gp",lookup_field="group_id",lookup_url_kwarg="pk")
28 class Meta:
29 model = models.UserInfo
30 fields = ["id","username","password","group"]
31 depth = 0
32 #4.UserInfosView使用序列化器
33 def get(self, request, *args, **kwargs):
34 ser = UserInfoSerializer4(instance=user,many=True,context={"request":request})
35 #当访问UserInfosView视图类对应路由
6序列化源码分析


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
对请求数据进行验证:
序列化之数据效验
内置效验方法和自定义效验和钩子函数


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("提交数据")
序列化之源码分析:
源码小技巧,当源码中有类实例化,一般将数据进行封装,封装成一个对象。一大堆赋值过程。有__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
数据效验源码分析
1 #is_valid()
2 def is_valid(self, raise_exception=False):
3 ...
4 if not hasattr(self, '_validated_data'):
5 try:
6 #执行run_validation方法,此时注意要执行自己类的run_validation,为Serializer
7 self._validated_data = self.run_validation(self.initial_data)
8 except ValidationError as exc:
9 self._validated_data = {}
10 self._errors = exc.detail
11 else:
12 self._errors = {}
13
14 if self._errors and raise_exception:
15 raise ValidationError(self.errors)
16
17 return not bool(self._errors)
18 #--------------------------------------------------------------------
19 def run_validation(self, data=empty):
20 (is_empty_value, data) = self.validate_empty_values(data)
21 if is_empty_value:
22 return data
23 #执行to_internal_value方法
24 value = self.to_internal_value(data)
25 try:
26 self.run_validators(value)
27 value = self.validate(value)
28 assert value is not None, '.validate() should return the validated data'
29 except (ValidationError, DjangoValidationError) as exc:
30 raise ValidationError(detail=as_serializer_error(exc))
31
32 return value
33 #----------------------------------------------------------------------
34 def to_internal_value(self, data):
35 if not isinstance(data, Mapping):
36 message = self.error_messages['invalid'].format(
37 datatype=type(data).__name__
38 )
39 raise ValidationError({
40 api_settings.NON_FIELD_ERRORS_KEY: [message]
41 }, code='invalid')
42
43 ret = OrderedDict()
44 errors = OrderedDict()
45 fields = self._writable_fields
46
47 for field in fields:
48 validate_method = getattr(self, 'validate_' + field.field_name, None)
49 primitive_value = field.get_value(data)
50 try:
51 #执行字段本身内置方法。
52 validated_value = field.run_validation(primitive_value)
53 if validate_method is not None:
54 #执行验证的钩子方法
55 validated_value = validate_method(validated_value)
56 except ValidationError as exc:
57 errors[field.field_name] = exc.detail
58 except DjangoValidationError as exc:
59 errors[field.field_name] = get_error_detail(exc)
60 except SkipField:
61 pass
62 else:
63 set_value(ret, field.source_attrs, validated_value)
64
65 if errors:
66 raise ValidationError(errors)
67
68 return ret
rest framework 学习 序列化的更多相关文章
- Entity Framework 学习整理(分播客整理)
MSDN: http://msdn.microsoft.com/en-us/data/aa937723 台湾博客: http://www.dotblogs.com.tw/yc421206/ http: ...
- Entity Framework 学习笔记(2)
上期回顾:Entity Framework 学习笔记(1) Entity Framework最主要的东西,就是自己创建的.继承于DbContext的类: /// <summary> /// ...
- Zend Framework学习日记(2)--HelloWorld篇(转)
Zend Framework学习日记(2)--HelloWorld篇 这一篇主要演示如何用zf命令行工具建立一个基于Zend Framework框架的工程,也是我初学Zend Framework的小练 ...
- Zend Framework学习日记(1)--环境搭建篇(转)
Zend Framework学习日记(1)--环境搭建篇 (1)开发工具 Zend Framework框架:http://framework.zend.com/download/latest 包含2个 ...
- Entity Framework学习笔记
原文地址:http://www.cnblogs.com/frankofgdc/p/3600090.html Entity Framework学习笔记——错误汇总 之前的小项目做完了,到了总结经验和 ...
- Entity Framework 学习中级篇1—EF支持复杂类型的实现
本节,将介绍如何手动构造复杂类型(ComplexType)以及复杂类型的简单操作. 通常,复杂类型是指那些由几个简单的类型组合而成的类型.比如:一张Customer表,其中有FristName和Las ...
- MVC5 Entity Framework学习
MVC5 Entity Framework学习(1):创建Entity Framework数据模型 MVC5 Entity Framework学习(2):实现基本的CRUD功能 MVC5 Entity ...
- robot framework学习二-----元素定位
文章摘自:https://www.cnblogs.com/fnng/p/3901391.html 不要误认为Robot framework 只是个web UI测试工具,更正确的理解Robot fram ...
- Django Rest framework 之 序列化
RESTful 规范 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest framework 之 节流(三) ...
- Entity Framework学习初级篇2
Entity Framework 学习初级篇2--ObjectContext.ObjectQuery.ObjectStateEntry.ObjectStateManager类的介绍 本节,简单的介绍E ...
随机推荐
- 7个角度,用 ChatGPT 玩转机器学习
大家好,我是机器学习科普创作者章北海mlpy,探索更高效的学习方法是我一直等追求.现在的初学者太幸福了,可以利用ChatGPT来帮助你学习机器学习的各个方面. 比如[个人首测]百度文心一言 VS GP ...
- Java面试——不安全的集合类
Java 中有许多的集合,常用的有List,Set,Queue,Map. 其中 List,Set,Queue都是Collection(集合),List<String>中<>的内 ...
- Java面试——RPC
一.RPC 服务的原理 [1]Socket 套接字:网络上的两个程序通过一个双向的通信连接实现数据的交换,这个链接的一端称为 Socket.可以实现不同计算机之间的通信,是网络编程接口的具体实现.So ...
- C#多线程开发-了解C#5.0 05
前面一篇文章,了解了任务并行库.这是异步编程基础设施,它允许我们以模块化的方式设计程序,来组合不同的异步操作.解决了以往线程之间传递消息难等问题,但是我们在阅读和编写此类程序时还是会觉得非常难理解程序 ...
- void关键字
在C++中,void表示为无类型,主要有三个用途: (1)函数的 返回值用void,表示函数没有返回值. void func(int a, int b) { //函数体代码 return; } (2) ...
- 字符串算法--$\mathcal{KMP,Trie}$树
\(\mathcal{KMP算法}\) 实际上,完全没必要从\(S\)的每一个字符开始,暴力穷举每一种情况,\(Knuth.Morris\)和\(Pratt\)对该算法进行了改进,称为KMP算法. 而 ...
- 基于express、node与mongodb写后端接口
1.首先运行mongodb,建立一个数据库.(前提是你的电脑已经装了mongodb) 先打开一个命令窗口打开mongodb cd /usr/localcd mongodb/bin./mongod -- ...
- ACM-NEFU-2020大一寒假培训三(暴力)
A.二倍的问题 Description 给定2到15个不同的正整数,你的任务是计算这些数里面有多少个数对满足:数对中一个数是另一个数的两倍.比如给定1 4 3 2 9 7 18 22,得到的答案是3, ...
- Python简易学生管理系统
目录结构: 1. 学生文件 student.py # 学生类 class Student(object): # 存放学生信息 student_info = {} # 学生初始化方法 def __ini ...
- Python GDAL库在Anaconda环境中的配置
本文介绍在Anaconda环境下,安装Python中栅格.矢量等地理数据处理库GDAL的方法. 需要注意的是,本文介绍基于conda install命令直接联网安装GDAL库的方法:这一方法有 ...