Marshmallow

官方文档:https://marshmallow.readthedocs.io/en/latest/

Marshmallow,中文译作:棉花糖。是一个轻量级的数据格式转换的模块,也叫序列化和反序列化模块,常用于将复杂的orm模型对象与python原生数据类型之间相互转换。marshmallow提供了丰富的api功能。如下:

  1. Serializing

    序列化[可以把数据对象转化为可存储或可传输的数据类型,例如:objects/object->list/dict,dict/list->string]

  2. Deserializing

    反序列化器[把可存储或可传输的数据类型转换成数据对象,例如:list/dict->objects/object,string->dict/list]

  3. Validation

    数据校验,可以在反序列化阶段,针对要转换数据的内容进行类型验证或自定义验证。

Marshmallow本身是一个单独的库,基于我们当前项目使用框架是flask并且数据库ORM框架使用SQLAlchemy,所以我们可以通过安装flask-sqlalchemy和marshmallow-sqlalchemy集成到项目就可以了。

基本安装和配置

模块安装:

pip install -U marshmallow-sqlalchemy
pip install -U flask-sqlalchemy
pip install -U flask-marshmallow

模块初始化:

import osfrom flask import Flask
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy
from flask_redis import FlaskRedis
from flask_session import Session
from flask_migrate import Migrate,MigrateCommand
from flask_jsonrpc import JSONRPC
from flask_marshmallow import Marshmallowfrom application.utils import init_blueprint
from application.utils.config import load_config
from application.utils.session import init_session
from application.utils.logger import Log
from application.utils.commands import load_command
# 创建终端脚本管理对象
manager = Manager()# 创建数据库链接对象
db = SQLAlchemy()# redis链接对象
redis = FlaskRedis()# Session存储对象
session_store = Session()# 数据迁移实例对象
migrate = Migrate()# 日志对象
log = Log()# jsonrpc模块实例对象
jsonrpc = JSONRPC()# 数据转换器的对象创建
ma = Marshmallow()def init_app(config_path):"""全局初始化"""# 创建app应用对象app = Flask(__name__)# 项目根目录app.BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))# 加载配置Config = load_config(config_path)app.config.from_object(Config)# 数据库初始化db.init_app(app)redis.init_app(app)# 数据转换器的初始化ma.init_app(app)# session存储初始化init_session(app)session_store.init_app(app)# 数据迁移初始化migrate.init_app(app,db)# 添加数据迁移的命令到终端脚本工具中manager.add_command('db', MigrateCommand)# 日志初始化app.log = log.init_app(app)# 蓝图注册init_blueprint(app)# jsonrpc初始化jsonrpc.service_url = "/api" # api接口的url地址前缀jsonrpc.init_app(app)# 初始化终端脚本工具manager.app = app# 注册自定义命令load_command(manager)return manager

为了方便学习和使用Marshllow, 我们单独创建一个marsh蓝图来验证这个模块的基本使用.

cd application/apps
python ../../manage.py blue -n marsh

注册marsh模块,application.settings.dev代码:

    INSTALLED_APPS = ["application.apps.home","application.apps.users","application.apps.marsh",]

总路由,application.urls 代码:

from application.utils import include
urlpatterns = [include("","home.urls"),include("/users","users.urls"),include("/marsh","marsh.urls"),
]

视图application.apps.marsh.views代码:

from marshmallow import Schema,fields
from application.apps.users.models import User,UserProfile
class UserSchema(Schema):name   = fields.String()age    = fields.Integer()email  = fields.Email()money  = fields.Number()class Meta:fields = ["name","age","money","email","info"]ordered = True # 转换成有序字典def index():"""序列化"""return "ok" # flask==1.1.1以后,可以直接返回字典数据,flask1.0以前必须通过jsonify返回字典

子路由,application.apps.marsh.urls,代码:

from . import views
from application.utils import path
urlpatterns = [path("", views.index),
]

基本构造器(Schema)

marshmallow转换数据格式主要通过构造器类来完成,而Schema类提供了数据转换的基本功能:序列化,验证和反序列化。所以在使用marshmallow的过程中所有的构造器类必须直接或间接继承于Schema基类

基于Schema完成数据序列化转换

application.apps.marsh.views代码:

from marshmallow import Schema,fields
from application.apps.users.models import User,UserProfile
class UserSchema(Schema):name   = fields.String()age    = fields.Integer()email  = fields.Email()money  = fields.Number()class Meta:fields = ["name","age","money","email","info"]ordered = True # 转换成有序字典def index():"""序列化""""""单个模型数据的序列化处理"""user1 = User( name="xiaoming", password="123456", age=16, email="333@qq.com", money=31.50 )# print(user1)# 把模型对象转换成字典格式data1 = UserSchema().dump(user1)print(type(data1),data1)# 把模型对象转换成json字符串格式data2 = UserSchema().dumps(user1)print(type(data2), data2)return "ok"

schema常用属性数据类型

类型 描述
fields.Dict(keys, type]] = None, values, …) 字典类型,常用于接收json类型数据
fields.List(cls_or_instance, type], **kwargs) 列表类型,常用于接收数组数据
fields.Tuple(tuple_fields, *args, **kwargs) 元组类型
fields.String(*, default, missing, data_key, …) 字符串类型
fields.UUID(*, default, missing, data_key, …) UUID格式类型的字符串
fields.Number(*, as_string, **kwargs) 数值基本类型
fields.Integer(*, strict, **kwargs) 整型
fields.Decimal(places, rounding, *, allow_nan, …) 数值型
fields.Boolean(*, truthy, falsy, **kwargs) 布尔型
fields.Float(*, allow_nan, as_string, **kwargs) 浮点数类型
fields.DateTime(format, **kwargs) 日期时间类型
fields.Time(format, **kwargs) 时间类型
fields.Date(format, **kwargs) 日期类型
fields.Url(*, relative, schemes, Set[str]]] = None, …) url网址字符串类型
fields.Email(*args, **kwargs) 邮箱字符串类型
fields.IP(*args[, exploded]) IP地址字符串类型
fields.IPv4(*args[, exploded]) IPv4地址字符串类型
fields.IPv6(*args[, exploded]) IPv6地址字符串类型
fields.Method(serialize, deserialize, **kwargs) 基于Schema类方法返回值的字段
fields.Function(serialize, Any], Callable[[Any, …) 基于函数返回值得字段
fields.Nested(nested, type, str, Callable[[], …) 外键类型

Schema数据类型的常用通用属性

属性名 描述
default 序列化阶段中设置字段的默认值
missing 反序列化阶段中设置字段的默认值
validate 反序列化阶段调用的内置数据验证器或者内置验证集合
required 设置当前字段的必填字段
allow_none 是否允许为空
load_only 是否在反序列化阶段才使用到当前字段
dump_omly 是否在序列化阶段才使用到当前字段
error_messages 字典类型,可以用来替代默认的字段异常提示语,格式:
error_messages={“required”: “用户名为必填项。”}

在前面进行的序列化操作属于序列化单个数据对象, MarshMallow中也可以进行多个数据对象的序列化.

from marshmallow import Schema,fields
from application.apps.users.models import User,UserProfileclass UserSchema(Schema):name   = fields.String()age    = fields.Integer()email  = fields.Email()money  = fields.Number()class Meta:fields = ["name","age","money","email","info"]ordered = True # 转换成有序字典def index():"""序列化""""""多个模型数据的序列化"""user1 = User(name="xiaoming", password="123456", age=15, email="333@qq.com", money=31.50)user2 = User(name="xiaohong", password="123456", age=16, email="333@qq.com", money=31.50)user3 = User(name="xiaopang", password="123456", age=17, email="333@qq.com", money=31.50)data_list = [user1,user2,user3]data1 = UserSchema(many=True).dumps(data_list)print(type(data1),data1)return "ok"

构造器嵌套使用

application.apps.marsh.views,代码:

from marshmallow import Schema,fields
from application.apps.users.models import User,UserProfile
class UserProfileSchema(Schema):education = fields.Integer()middle_school = fields.String()class UserSchema(Schema):name   = fields.String()age    = fields.Integer()email  = fields.Email()money  = fields.Number()info   = fields.Nested(UserProfileSchema,only=["middle_school"])class Meta:fields = ["name","age","money","email","info"]ordered = True # 转换成有序字典def index():"""序列化""""""序列化嵌套使用"""user1 = User(name="xiaoming", password="123456", age=15, email="333@qq.com", money=31.50)user1.info = UserProfile(education=3,middle_school="北京师范学院附属中学白沙路分校")data = UserSchema().dump(user1)data = UserSchema().dumps(user1)print(data)return "ok"

基于Schema完成数据反序列化转换

代码:

from marshmallow import Schema, fields, validate, ValidationError,post_load
class UserSchema2(Schema):name = fields.String()sex = fields.String()age = fields.Integer(missing=18)email = fields.Email()mobile = fields.String()@post_loaddef post_load(self, data, **kwargs):return User(**data)def index():user_data = {"mobile":"1331345635","name": "xiaoming", "email": "xiaoming@qq.com","sex":"abc"}us2 = UserSchema2()result = us2.load(user_data)print(result)  # ==> <User xiaoming>return "ok"

反序列化时转换/忽略部分数据

from marshmallow import Schema, fields, validate, ValidationError,post_load
class UserSchema2(Schema):name = fields.String()sex = fields.String()age = fields.Integer(missing=18)email = fields.Email()mobile = fields.String(required=True)@post_loaddef post_load(self, data, **kwargs):return User(**data)def index():user_data = {"name": "xiaoming","sex":"abc"}us2 = UserSchema2()result = us2.load(user_data,partial=True)print(result)  # ==> <User xiaoming>return "ok"

设置字段只在序列化或反序列化阶段才启用

from marshmallow import Schema, fields, validate, ValidationError,post_load
class UserSchema2(Schema):name = fields.String()sex = fields.Integer(validate=validate.OneOf([0,1,2]))age = fields.Integer(missing=18)email = fields.Email()mobile = fields.String()password = fields.String(load_only=True) # 设置当前字段为只写字段 "write-only",在反序列化启用created_time = fields.DateTime(dump_only=True) # 相当于只读字段 "read-only"@post_loaddef post_load(self, data, **kwargs):return User(**data)def index():user_data = {"name": "xiaoming","password":"123456","sex":1}us2 = UserSchema2()# 反序列化result = us2.load(user_data)print(result)  # ==> <User xiaoming># 序列化us3 = UserSchema2(only=["sex","name","age"]) # 限制处理的字段result2 = us3.dump(result)print(result2)return "ok"

反序列化阶段的钩子方法

post_dump([fn,pass_many,pass_original]) 注册要在序列化对象后调用的方法,它会在对象序列化后被调用。
post_load([fn,pass_many,pass_original]) 注册反序列化对象后要调用的方法,它会在验证数据之后被调用。
pre_dump([fn,pass_many]) 注册要在序列化对象之前调用的方法,它会在序列化对象之前被调用。
pre_load([fn,pass_many]) 在反序列化对象之前,注册要调用的方法,它会在验证数据之前调用。

from marshmallow import Schema, fields, validate, ValidationError,post_load,post_dump
class UserSchema2(Schema):name = fields.String()sex = fields.Integer(validate=validate.OneOf([0,1,2]))age = fields.Integer(missing=18)email = fields.Email()mobile = fields.String()password = fields.String(load_only=True) # 设置当前字段为只写字段,只会在反序列化阶段启用@post_loaddef post_load(self, data, **kwargs):return User(**data)@post_dumpdef post_dump(self,data, **kwargs):data["mobile"] = data["mobile"][:3] +"*****"+ data["mobile"][-3:]return datadef index():user_data = {"name": "xiaoming","password":"123456","sex":1,"mobile":"133123454656"}us2 = UserSchema2()# 反序列化result = us2.load(user_data)print(result)  # ==> <User xiaoming># 序列化us3 = UserSchema2(only=["sex","name","age","mobile"]) # 限制处理的字段result2 = us3.dump(result)print(result2)return "ok"

反序列化阶段对数据进行验证

基于内置验证器进行数据验证

内置验证器 描述
validate.Email(*, error) 邮箱验证
validate.Equal(comparable, *, error) 判断值是否相等
validate.Length(min, max, *, equal, error) 值长度/大小验证
validate.OneOf(choices, labels, *, error) 选项验证
validate.Range([min, max]) 范围验证
validate.Regexp(regex, bytes, Pattern][, flags]) 正则验证
validate.URL(*, relative, schemes, Set[str]]] = None, …) 验证是否为URL

代码:

from marshmallow import Schema, fields, validate, ValidationError,post_load
class UserSchema3(Schema):name = fields.String(required=True)sex = fields.String(required=True,error_messages={"required":"对不起,permission必须填写"})age = fields.Integer(missing=18,validate=validate.Range(min=18,max=40,error="年龄必须在18-40之间!")) # 限制数值范围email = fields.Email(error_messages={"invalid":"对不起,必须填写邮箱格式!"})mobile = fields.String(required=True, validate=validate.Regexp("^1[3-9]\d{9}$",error="手机号码格式不正确"),error_messages={"Regexp":"手机格式不正确"})@post_loaddef make_user_obj(self, data, **kwargs):return User(**data)def index3():user_data = {"mobile":"1331345635","name": "xiaoming","age":40, "email": "xiaoming@qq.com","sex":"abc"}us2 = UserSchema3()result = us2.load(user_data)result2 = us2.dumps(result)print(result)print(result2)return "ok"

自定义验证方法

from marshmallow import Schema, fields, validate,validates, ValidationError,post_load,validates_schema
class UserSchema4(Schema):name = fields.String(required=True)sex = fields.String(required=True,error_messages={"required":"对不起,permission必须填写"})age = fields.Integer(missing=18,validate=validate.Range(min=18,max=40,error="年龄必须在18-40之间!")) # 限制数值范围email = fields.Email(error_messages={"invalid":"对不起,必须填写邮箱格式!"})mobile = fields.String(required=True, validate=validate.Regexp("^1[3-9]\d{9}$",error="手机号码格式不正确"),error_messages={"Regexp":"手机格式不正确"})password = fields.String(required=True, load_only=True)password2 = fields.String(required=True, allow_none=True)@post_loaddef make_user_obj(self, data, **kwargs):return User(**data)@validates("name")def validate_name(self,data,**kwargs):print("name=%s" % data)if data == "root":raise ValidationError({"对不起,root用户是超级用户!您没有权限注册!"})# 必须有返回值return data@validates_schemadef validate(self,data,**kwargs):print(data)if data["password"] != data["password2"]:raise ValidationError("密码和确认密码必须一样!")data.pop("password2")return datadef index():user_data = {"password":"12345","password2":"123456","mobile":"13313345635","name": "root1","age":40, "email": "xiaoming@qq.com","sex":"abc"}us2 = UserSchema4()result = us2.load(user_data)print(result)return "ok"

模型构造器(ModelSchema)

官方文档:https://github.com/marshmallow-code/marshmallow-sqlalchemy

​ https://marshmallow-sqlalchemy.readthedocs.io/en/latest/

注意:flask_marshmallow在0.12.0版本以后已经移除了ModelSchema和TableSchema这两个模型构造器类,官方转而推荐了使用SQLAlchemyAutoSchema和SQLAlchemySchema这2个类,前后两者用法类似。

创建

from marshmallow_sqlalchemy import SQLAlchemySchema,SQLAlchemyAutoSchema,auto_field
class UserSchema5(SQLAlchemySchema):# auto_field的作用,设置当前数据字段的类型和选项声明自动从模型中对应的字段中提取# name = auto_field()# 此处,数据库中根本没有username,需要在第一个参数位置,声明当前数据字典的类型和选项声明从模型的哪个字段提取的username = auto_field("name",dump_only=True)# 可以在原字段基础上面,增加或者覆盖模型中原来的声明created_time = auto_field(format="%Y-%m-%d")# 甚至可以声明一些不是模型的字段token = fields.String()class Meta:model = Userfields = ["username","created_time","token"]def index5():"""单个模型数据的序列化处理"""from datetime import datetimeuser1 = User(name="xiaoming",password="123456",age=16,email="333@qq.com",money=31.50,created_time= datetime.now(),)user1.token = "abc"# 把模型对象转换成字典格式data1 = UserSchema5().dump(user1)print(type(data1),data1)return "ok""""SQLAlchemySchema使用起来,虽然比上面的Schema简单许多,但是还是需要给小转换的字段全部统一写上才转换这些字段
,如果不想编写字段信息,直接从模型中复制,也可以使用SQLAlchemyAutoSchema。"""
class UserSchema6(SQLAlchemyAutoSchema):token = fields.String()class Meta:model = Userinclude_fk = False # 启用外键关系include_relationships = False # 模型关系外部属性fields = ["name","created_time","info","token"] # 如果要全换全部字段,就不要声明fields或exclude字段即可sql_session = db.sessiondef index():"""单个模型数据的序列化处理"""from datetime import datetimeuser1 = User(name="xiaoming",password="123456",age=16,email="333@qq.com",money=31.50,created_time= datetime.now(),info=UserProfile(position="助教"))# 把模型对象转换成字典格式user1.token="abcccccc"data1 = UserSchema6().dump(user1)print(type(data1),data1)return "ok"

浅析Marshmallow在flask中的应用相关推荐

  1. flask中的request

    1.request是什么? 简单来说,它就是flask的封装的一个对象,这个对象包含着前端请求所带的所有信息.既然说它是一个对象,那么它肯定是有一些熟悉,和方法的,下面就来介绍下request里的熟悉 ...

  2. python flask 表单数据输出_将数据从HTML表单发送到Flask中的Python脚本

    我的Python脚本中有下面的代码: def cmd_wui(argv, path_to_tx): """Run a web UI.""" ...

  3. 网络推广外包专员浅析网络推广外包中网站转化率的发展意义

    曾几何时,每当企业对同行企业网站充满向往之时,回首浏览自己的网站始终感觉差了不止一点两点,而这些差异就是影响企业网站转化率提升的重要原因.一旦企业网站转化率不佳,自然也无法达到为企业在开拓互联网网络营 ...

  4. 浅析网络营销外包中如何实现网络营销外包中的图片推广?

    随着时代的发展互联网中网站建设的要求也日趋严格,在搜索引擎算法的更新迭代中各行各业之间的企业网站竞争性也在逐渐增强,不过一些站长认为网站优化效果若想好更应该从图片素材中下功夫,可殊不知大量使用图片素材 ...

  5. 网络营销外包浅析网络营销外包中网站排名效果不佳的原因有哪些?

    在网络营销外包之中站长在定期监测网站排名效果时发现网站排名效果不佳,这意味着网站排名优化工作的某些环节出现问题,导致网站排名优化效果不明显,这让站长十分头疼,毕竟每天坚持优化却依然没有排名效果,这究竟 ...

  6. 网络营销专员浅析在网络营销中网站关键词对网站流量获取有何影响?

    网站上线后为确保正常运营和长久性的良性发展,可针对网站优化运营中的重点进行修改和调整,以满足日常网站运营发展的需求.那么在长期以来的网络营销发展中,网站关键词对网站流量获取是否有影响?如果有那又该如何 ...

  7. 网络营销专员浅析网络营销过程中如何做好网站权重流量的优化

    在搜索引擎中通过检索关键词后所展示出来的首页网站大多都有着不错的流量和权重,这对于企业网站来说是网站优化运营和网络营销推广专业水准的体现,这也是无数专业人士背后默默运营得出的结果.通常情况下,网站权重 ...

  8. 企业网络推广专员浅析企业网络推广中网站关键词排名优化有何技巧?

    自从企业网站上线运营之后,站长通过对企业网站自身定位规划的优化策略逐步展开优化进程,利用熟知的网站优化方法帮助企业网站快速获得搜索引擎收录,有了收录更能为用户呈现出企业网站优质的一面,获得良好排名助力 ...

  9. flask中的CBV , flask-session在redis中存储session , WTForms数据验证 , 偏函数 , 对象里的一些小知识...

    flask中的CBV , flask-session在redis中存储session , WTForms数据验证 , 偏函数 , 对象里的一些小知识 flask中的CBV写法 后端代码 # 导入vie ...

  10. 浅析SQL Server数据库中的伪列以及伪列的含义

    浅析SQL Server数据库中的伪列以及伪列的含义 原文:浅析SQL Server数据库中的伪列以及伪列的含义 本文出处:http://www.cnblogs.com/wy123/p/6833116 ...

最新文章

  1. p20适配鸿蒙系统,适配鸿蒙OS,必须要升级到EMUI 11?最新机型升级名单公布
  2. Struts2结果跳转方式
  3. 创建SQL函数计算员工加班时间
  4. CSS文件开头到底声明@charset utf-8
  5. 下载的字幕php是什么格式的,mkv是什么文件格式
  6. 雷军求别骂!小米9 Pro定价或许会很高
  7. 字符串压缩算法(腾讯笔试题)
  8. ODOO13 开发教程四 模型中的字段
  9. FindWithTag用法
  10. goahead 移植
  11. c语言单片机温度调节系统设计,基于单片机的温度控制系统的设计
  12. 【解决方案】Android开发填坑之RecyclerView刷新闪烁
  13. 图基准数据集(OGB)
  14. SwiftUI Core Haptics 基础教程
  15. 【故障处理】IMP-00010错误 12C的dmp文件导入11G
  16. 如何使用MATLAB将两张或者多张figure图形合并到一个figure图形里进行对比
  17. 【无私分享】修订版干货!!!一个炫酷的自定义日历控件,摆脱日历时间选择烦恼,纯福利~...
  18. nodejs html多语言切换,利用 nodejs 自动生成 Android 语言包实现应用内切换多语言的方案...
  19. Idea导出可运行jar包及运行方法
  20. 南非世界杯 小组赛 阿根廷vs尼日利亚

热门文章

  1. linux两块硬盘主从,电脑双硬盘双系统启动的顺序调整及设置方法
  2. Fedora9的虚拟机安装
  3. 微信小程序-云开发3云函数、云存储
  4. oracle固定资产部门分摊,用友软件操作手册--固定资产--多部门使用、分摊处理...
  5. 键盘定位板图纸_看看199的机械键盘可以有多酷
  6. 生产计划排产软件能为企业生产管理提供哪些帮助?
  7. 投入产出表分析(交通经济学作业)
  8. 爬虫之Scrapy文件爬取
  9. answer的汉语_answers怎么读(answers中文是什么意思)
  10. 2021 年年度蕞佳开源软件!