Flask Marshmallow基本使用

您所在的位置:网站首页 marshmallow棉花糖歌手 Flask Marshmallow基本使用

Flask Marshmallow基本使用

2024-07-14 19:34:02| 来源: 网络整理| 查看: 265

Marshmallow

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

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

Serializing

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

Deserializing

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

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 os from 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 Marshmallow from 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, 我们单独创建一个蓝图来验证这个模块的基本使用.

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

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

INSTALLED_APPS = [ "home", "users", "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"

子路由,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): # 基本构造器(Schema) '''转换用户信息 与模型无关 fields设置字段类型 ''' 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="[email protected]", money=31.50 ) # print(user1) # 把模型对象转换成字典格式 data1 = UserSchema().dump(user1) print(type(data1),data1) # 把模型对象转换成json字符串格式 data2 = UserSchema().dumps(user1) # dumps把任意对象序列化成一个str 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,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=15, email="[email protected]", money=31.50) user2 = User(name="xiaohong", password="123456", age=16, email="[email protected]", money=31.50) user3 = User(name="xiaopang", password="123456", age=17, email="[email protected]", money=31.50) data_list = [user1,user2,user3] data1 = UserSchema(many=True).dumps(data_list) # dumps把任意对象序列化成一个str many=True 允许多个模型序列化 print(type(data1),data1) # [{"name": "xiaoming", "age": 4, "money": 31.5, "email": "[email protected]", "info": null}, {"name": "xiaohui", "age": 5, "money": 66.5, "email": "[email protected]", "info": null}, {"name": "xiaobai", "age": 6, "money": 88.5, "email": "[email protected]", "info": null}] 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"]) # nested外键类型 only只显示某个字段 class Meta: fields = ["name","age","money","email","info"] ordered = True # 转换成有序字典 def index(): """序列化""" """序列化嵌套使用""" user1 = User(name="xiaoming", password="123456", age=15, email="[email protected]", money=31.50) user1.info = UserProfile( education=3, middle_school="qwq学校" ) data = UserSchema().dump(user1) # order排序之后的字典 print(data) # OrderedDict([('name', 'xiaoming'), ('age', 15), ('money', 31.5), ('email', '[email protected]'), ('info', {'middle_school': 'qwq学校'})]) data1 = UserSchema().dumps(user1) # 对象转字符串 print(data1) # {"name": "xiaoming", "age": 15, "money": 31.5, "email": "[email protected]", "info": {"middle_school": "qwq\u5b66\u6821"}} return "ok" 基于Schema完成数据反序列化转换

代码:

class UserSchema2(Schema): name = fields.String(required=True,error_messages={"required":"必须填写"}) # required=True 必须要传的参数,没有则error sex = fields.String() age = fields.Integer(missing=18) # 反序列化时设置默认值 email = fields.Email(error_messages={'invalid':"对不起,必须正确填写邮箱格式化!"}) mobile = fields.String() @post_load # 反序列化成一个对象,给schema的一个方法加上post_load装饰器 def post_load(self, data, **kwargs): return User(**data) def index(): user_data = {"mobile":"1331345635", "email": "[email protected]","sex":"abc"} us2 = UserSchema2() result = us2.load(user_data,partial=True) # 默认序列化器必须传递所有required的字段,否则会抛出验证异常。但是我们可以使用partial=True,来避免报错 print(result) # ==> 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_load def 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) # 默认序列化器必须传递所有required的字段,否则会抛出验证异常。但是我们可以使用partial参数来允许部分字段更新 print(result) # ==> return "ok" 设置字段只在序列化或反序列化阶段才启用 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" 只会在反序列化阶段启用 # password = fields.String(dump_only=True) # 设置当前字段为只写字段,"read-only" 只会在序列化阶段启用 @post_load def 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) # ==> # 序列化 us3 = UserSchema2(only=["sex","name","age","password"]) # 限制处理的字段 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_load def post_load(self, data, **kwargs): return User(**data) @post_dump def post_dump(self,data, **kwargs): data["mobile"] = data["mobile"][:3] +"*****"+ data["mobile"][-3:] return data def index(): user_data = {"name": "xiaoming","password":"123456","sex":1,"mobile":"133123454656"} us2 = UserSchema2() # 反序列化 result = us2.load(user_data) print(result) # ==> # 序列化 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_load def make_user_obj(self, data, **kwargs): return User(**data) def index3(): user_data = {"mobile":"1331345635","name": "xiaoming","age":40, "email": "[email protected]","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_load def 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_schema def validate(self,data,**kwargs): print(data) if data["password"] != data["password2"]: raise ValidationError("密码和确认密码必须一样!") data.pop("password2") return data def index(): user_data = {"password":"12345","password2":"123456","mobile":"13313345635","name": "root1","age":40, "email": "[email protected]","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个类,前后两者用法类似。

创建

class UserSchema(SQLAlchemyAutoSchema): class Meta: model = 模型类名 # table = models.Album.__table__ include_relationships = True # 输出模型对象时同时对外键,是否也一并进行处理 include_fk = True # 序序列阶段是否也一并返回主键 load_instance = True # 反序列化阶段时,直接返回模型对象 sql_session = db.session # 数据库连接会话对象 # fields= ["id","name"] # 启动的字段列表 exclude = ["id","name"] # 排除字段列表 模型构造器(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 from marshmallow import Schema, fields from application.apps.user.models import User, UserProfile, db from marshmallow import Schema, fields, validate, ValidationError,post_load class UserSchema5(SQLAlchemySchema): # auto_field的作用,设置当前数据字段的类型和选项声明自动从模型中对应的字段中提取 # name = auto_field() # 此处,数据库中根本没有username,需要在第一个参数位置,声明当前数据字典的类型和选项声明从模型的哪个字段提取的 username = auto_field("name",dump_only=True) # 可以在原字段基础上面,增加或者覆盖模型中原来的声明 created_time = auto_field(format="%Y-%m-%d") # format 设置时间格式 # 甚至可以声明一些不是模型的字段 token = fields.String() class Meta: model = User fields = ["username","created_time","token"] def index5(): """单个模型数据的序列化处理""" from datetime import datetime user1 = User( name="xiaoming", password="123456", age=16, email="[email protected]", money=31.50, created_time= datetime.now(), ) user1.token = "abc" # 把模型对象转换成字典格式 data1 = UserSchema5().dump(user1) print(type(data1),data1) # {'username': 'xiaoming', 'token': 'abc', 'created_time': '2020-12-02'} return "ok" """SQLAlchemySchema使用起来,虽然比上面的Schema简单许多,但是还是需要给小转换的字段全部统一写上才转换这些字段 ,如果不想编写字段信息,直接从模型中复制,也可以使用SQLAlchemyAutoSchema。""" class UserSchema6(SQLAlchemyAutoSchema): token = fields.String() class Meta: model = User include_fk = False # 启用外键关系 include_relationships = False # 模型关系外部属性 fields = ["name","created_time","info","token"] # 如果要全换全部字段,就不要声明fields或exclude字段即可 sql_session = db.session def index(): """单个模型数据的序列化处理""" from datetime import datetime user1 = User( name="xiaoming", password="123456", age=16, email="[email protected]", money=31.50, created_time= datetime.now(), info=UserProfile(position="助教") ) # 把模型对象转换成字典格式 user1.token="abcccccc" data1 = UserSchema6().dump(user1) print(type(data1),data1) # class 'dict'> {'info': , 'created_time': '2020-12-02T17:47:21.821940', 'token': 'abcccccc', 'name': 'xiaoming'} return "ok"


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭