0. Marshmallow背景介绍
介绍
- Marshmallow,中文译作:棉花糖。
- 是一个轻量级的数据格式转换的模块,也叫序列化和反序列化模块,常用于将复杂的orm模型对象与python原生数据类型之间相互转换。
- 一般用于flask
- marshmallow提供了丰富的api功能。如下:
Serializing
序列化[可以把数据对象转化为可存储或可传输的数据类型,例如:objects/object->list/dict,dict/list->string]
Deserializing
反序列化器[把可存储或可传输的数据类型转换成数据对象,例如:list/dict->objects/object,string->dict/list]
Validation
数据校验,可以在反序列化阶段,针对要转换数据的内容进行类型验证或自定义验证。
官方文档:
1. 使用
1. 安装
pip3 install -U marshmallow-sqlalchemy -i https://pypi.douban.com/simple
pip3 install -U flask-sqlalchemy -i https://pypi.douban.com/simple
pip3 install -U flask-marshmallow -i https://pypi.douban.com/simple
pip3 install -U pymysql -i https://pypi.douban.com/simple
2. flask连接mysql介绍
# 格式
"mysql://用户名:密码@ip:端口/库名称?charset=utf8mb4"
# 案例
"mysql://root:foobared@106.14.42.253:3308/mofangapp?charset=utf8mb4"
3. 模块初始化:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
from datetime import datetime
import pymysql
pymysql.install_as_MySQLdb()
# 实例化
app = Flask(__name__)
# 配置数据库
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:foobared@106.14.42.253:3308/mofangapp?charset=utf8mb4"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
# 实例化
db = SQLAlchemy()
ma = Marshmallow()
# 注册
db.init_app(app)
ma.init_app(app)
class User(db.Model):
__tablename__ = "tb_user"
id = db.Column(db.Integer, primary_key=True, comment="主键ID")
username = db.Column(db.String(255), index=True, comment="用户名")
password = db.Column(db.String(255), comment="登录密码")
mobile = db.Column(db.String(15), index=True, comment="手机号码")
sex = db.Column(db.Boolean, default=True, comment="性别")
email = db.Column(db.String(255), index=True, comment="邮箱")
created_time = db.Column(db.DateTime, default=datetime.now, comment="创建时间")
updated_time = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now, comment="更新时间")
def __repr__(self):
return "<%s: %s>" % (self.__class__.name, self.username)
@app.route("/")
def index():
return "hello"
if __name__ == '__main__':
with app.app_context():
# db.drop_all()
db.create_all()
app.run(debug=True, host='127.0.0.1', port=7800)
4. Marshmallow序列化基础使用
- 只有4.1是完整的代码,其他的只提供Marshmallow的代码,初始化的代码,就不在重复写了
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 | 是否允许为空 None,"" |
load_only | 是否在反序列化阶段才使用到当前字段,相当于之前的write_only |
dump_only | 是否在序列化阶段才使用到当前字段,相当于之前的read_only |
error_messages | 字典类型,可以用来替代默认的字段异常提示语,格式: error_messages={“required”: “用户名为必填项。”} |
单个表模型序列化成字典或json字符串
- 代码
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
from datetime import datetime
import pymysql
pymysql.install_as_MySQLdb()
# 实例化
app = Flask(__name__)
# 配置数据库
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:foobared@106.14.42.253:3308/mofangapp?charset=utf8mb4"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
# 实例化
db = SQLAlchemy()
ma = Marshmallow()
# 注册
db.init_app(app)
ma.init_app(app)
class User(db.Model):
__tablename__ = "tb_user"
id = db.Column(db.Integer, primary_key=True, comment="主键ID")
username = db.Column(db.String(255), index=True, comment="用户名")
password = db.Column(db.String(255), comment="登录密码")
mobile = db.Column(db.String(15), index=True, comment="手机号码")
sex = db.Column(db.Boolean, default=True, comment="性别")
email = db.Column(db.String(255), index=True, comment="邮箱")
created_time = db.Column(db.DateTime, default=datetime.now, comment="创建时间")
updated_time = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now, comment="更新时间")
def __repr__(self):
return "<%s: %s>" % (self.__class__.name, self.username)
# marshmallow转换数据格式主要通过架构转换类来完成.
# 在marshmallow使用过程中所有的架构转换类必须直接或间接继承于Schema基类
# 导入基类Schema--->继承 fields--->字段
from marshmallow import Schema, fields
# 类似与django的from组件
class UserSchema(Schema):
username = fields.String()
mobile = fields.String()
email = fields.Email()
create_time = fields.DateTime()
@app.route("/")
def index():
# 模拟数据
user = User(
username="xiaoming",
mobile="13312345677",
sex=True,
email="133123456@qq.com",
created_time=datetime.now(),
updated_time=datetime.now()
)
# 调用marsh把模型转换成python基本数据格式[字典/列表]
us = UserSchema()
# 转换成字典
ret1 = us.dump(user)
# 转换成json字符串(它是双引号的)
ret2 = us.dumps(user)
print(">>>> 原生 --> 对象")
print(User)
print(">>>> us.dump(user) --> 字典")
print(ret1)
print(">>>> us.dumps(user) --> json字符串")
print(ret2)
return "hello"
if __name__ == '__main__':
with app.app_context():
# db.drop_all()
db.create_all()
app.run(debug=True, host='127.0.0.1', port=7800)
- 输出
>>>> 原生 --> 对象
<class '__main__.User'>
>>>> us.dump(user) --> 字典
{'username': 'xiaoming', 'mobile': '13312345677', 'email': '133123456@qq.com'}
>>>> us.dumps(user) --> json字符串
{"username": "xiaoming", "mobile": "13312345677", "email": "133123456@qq.com"}
多个表模型序列化成字典或json字符串
- 代码
# marshmallow转换数据格式主要通过架构转换类来完成.
# 在marshmallow使用过程中所有的架构转换类必须直接或间接继承于Schema基类
# 导入基类Schema--->继承 fields--->字段
from marshmallow import Schema, fields
# 类似与django的from组件
class UserSchema(Schema):
username = fields.String()
mobile = fields.String()
email = fields.Email()
create_time = fields.DateTime()
@app.route("/")
def index():
# 模拟数据
user = User(
username="xiaoming",
mobile="13312345677",
sex=True,
email="133123456@qq.com",
created_time=datetime.now(),
updated_time=datetime.now()
)
user1 = User(
username="xiaoming1号",
mobile="13312345677",
sex=True,
email="133123456@qq.com",
created_time=datetime.now(),
updated_time=datetime.now()
)
user2 = User(
username="xiaoming2号",
mobile="13312345677",
sex=True,
email="133123456@qq.com",
created_time=datetime.now(),
updated_time=datetime.now()
)
user_list = [user, user1, user2]
us = UserSchema()
data_list = us.dump(user_list, many=True)
print(data_list)
return "hello"
if __name__ == '__main__':
with app.app_context():
# db.drop_all()
db.create_all()
app.run(debug=True, host='127.0.0.1', port=7800)
- 输出
[
{'username': 'xiaoming', 'mobile': '13312345677', 'email': '133123456@qq.com'},
{'username': 'xiaoming1号', 'mobile': '13312345677', 'email': '133123456@qq.com'},
{'username': 'xiaoming2号', 'mobile': '13312345677', 'email': '133123456@qq.com'}
]
5. 高级使用
序列化嵌套
- 代码
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
from datetime import datetime
import pymysql
pymysql.install_as_MySQLdb()
# 实例化
app = Flask(__name__)
# 配置数据库
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:foobared@106.14.42.253:3308/mofangapp?charset=utf8mb4"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
# 实例化
db = SQLAlchemy()
ma = Marshmallow()
# 注册
db.init_app(app)
ma.init_app(app)
# marshmallow转换数据格式主要通过架构转换类来完成.
# 在marshmallow使用过程中所有的架构转换类必须直接或间接继承于Schema基类
# 导入基类Schema--->继承 fields--->字段
from marshmallow import Schema, fields, ValidationError, validates_schema, validates, validate
"""
模拟表类型
User表中有两个外键 friends/books
Blog 有一个外键 author
"""
class User(object):
def __init__(self, name, email):
self.name = name
self.email = email
self.created_at = datetime.now()
self.books = []
self.friends = []
class Blog(object):
def __init__(self, title, author):
self.title = title
self.author = author # 用来代替MySQL中的外键关系
class BlogSchema(Schema):
title = fields.String()
# 使用lambda匿名函数,使只有在使用author时才会找UserSchema对象,不然可能出现先后调用,导致对象找不到的情况出现
# 用来序列化外键对象,可以将外键对象按照指定的格式进行序列化,并且外键指定的格式可以完成任何支持的marshmallow操作
author = fields.Nested(lambda: UserSchema())
class UserUserSchema(Schema):
name = fields.String()
email = fields.String()
class UserSchema(Schema):
name = fields.String()
email = fields.Email()
created_at = fields.DateTime(format='%Y-%m-%d %H:%M:%S')
# 双向嵌套,例如找出所有属于该用户的所有书籍。注意:在大数据量时,数据返回将非常慢
books = fields.List(fields.Nested(BlogSchema(exclude=("author",))))
# friends = fields.Nested(UserUserSchema(many=True)) # 方式一:使用一个外部的图式,可以指点序列化哪些字段
friends = fields.Nested("self", only=("name",), many=True) # 方式二:使用自身图式作为外键的方式,并指定序列化的字段
# friends = fields.Nested(lambda: UserSchema(many=True, only=("name",)), dump_only=True) # 方式二的一种:使用自身图式作为外键的图式,并指定序列化的字段
# friends = fields.Pluck("self", "name", many=True) # 方式三:使用Pluck字段可以用单个值来替换嵌套的数据。
@app.route("/")
def index():
try:
user0 = User(name="南派三叔", email="sanshu@163.com")
user1 = User(name="刘慈欣", email="sanshu@163.com")
user2 = User(name="天下霸唱", email="sanshu@163.com")
blog = Blog(title="盗墓笔记", author=user0)
res1 = BlogSchema().dump(blog)
# print(res, type(res))
print(res1)
user0.books = [blog]
user0.friends.append(user1)
user0.friends.append(user2)
res2 = UserSchema().dump(user0)
print(res2)
except Exception as err:
print(err)
return "hello"
if __name__ == '__main__':
with app.app_context():
# db.drop_all()
db.create_all()
app.run(debug=True, host='127.0.0.1', port=7800)
- 输出
{'author': {'name': '南派三叔',
'friends': [],
'created_at': '2022-04-09 14:04:05', 'email': 'sanshu@163.com',
'books': []},
'title': '盗墓笔记'
}
{'name': '南派三叔',
'friends': [{'name': '刘慈欣'}, {'name': '天下霸唱'}],
'created_at': '2022-04-09 14:04:05', 'email': 'sanshu@163.com',
'books': [{'title': '盗墓笔记'}]
}
反序列化
- 代码
from flask import Flask
from flask_marshmallow import Marshmallow
app = Flask(__name__)
ma = Marshmallow()
# 注册
ma.init_app(app)
# 反序列化
from marshmallow import Schema, fields, validate, ValidationError
class UserSchema(Schema):
# Str<--->String
name = fields.Str(validate=validate.Length(min=1))
permission = fields.Str(validate=validate.OneOf(["read", "write", "admin"]))
age = fields.Int(validate=validate.Range(min=18, max=40))
@app.route("/")
def index():
user_data = {"name": "Ronnie", "age": 18, "permission": "admin"}
schema = UserSchema()
result = schema.load(user_data)
print(result, type(result)) # => <User: 'Ronnie'>
return "hello"
if __name__ == '__main__':
app.run(debug=True, host='127.0.0.1', port=7800)
- 输出
{'age': 18, 'name': 'Ronnie', 'permission': 'admin'}
反序列化时转换/忽略部分数据
class UserSchema(Schema):
name = fields.String(required=True)
age = fields.Integer(required=True)
@app.route("/")
def index():
result = UserSchema().load({"age": 42}, partial=("name",))
print(result) # => {'age': 42}
return "ok"
设置字段只在序列化或反序列化阶段才启用
class UserSchema(Schema):
name = fields.Str()
# password is
password = fields.Str(load_only=True) # 相当于只写字段 "write-only"
created_time = fields.DateTime(dump_only=True) # 相当于只读字段 "read-only"
反序列化阶段的钩子方法
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 datetime import datetime
from flask import Flask
from flask_marshmallow import Marshmallow
from marshmallow import Schema,fields,validate,post_dump,post_load,pre_dump,pre_load
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"]="mysql://root:123@127.0.0.1:3306/mofangapp?charset=utf8mb4"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy()
db.init_app(app)
ma = Marshmallow()
ma.init_app(app)
class User(db.Model):
__tablename__ = "tb_user"
id = db.Column(db.Integer, primary_key=True, comment="主键ID")
name = db.Column(db.String(255), index=True, comment="用户名")
age = db.Column(db.Integer, comment="年龄")
password = db.Column(db.String(255), comment="登录密码")
mobile = db.Column(db.String(20), comment="手机号")
created_time = db.Column(db.DateTime, default=datetime.now, comment="创建时间")
def __repr__(self):
return "<%s: %s>" % (self.__class__.__name__, self.name)
class UserSchema(Schema):
name = fields.String(validate=validate.Length(min=1))
age = fields.Integer(required=True)
password = fields.Str(load_only=True) # 相当于只写字段 "write-only"
# created_time = fields.DateTime(dump_only=True) # 相当于只读字段 "read-only"
created_time = fields.DateTime(format='%Y-%m-%d %H:%M:%S')
mobile = fields.String()
@pre_load
def pre_load(self,data,**kwargs):
"""反序列化的前置钩子,会在数据验证之前执行"""
data["created_time"] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
return data
@post_load
def post_load(self,data,**kwargs):
"""反序列化钩子方法"""
data["password"] = generate_password_hash(data["password"])
return User(**data)
@post_dump
def post_dump(self,data,**kwargs):
"""序列化钩子方法"""
data["number"] = 1000
data["mobile"] = data["mobile"][:3]+"****"+data["mobile"][-4:]
return data
@app.route("/")
def index():
user_data = {"name": "小明", "age": 20,"password":"123456","mobile":"13312345678"} # 报错
us = UserSchema()
# 反序列化
instance = us.load(user_data)
print(instance) # <User: 小明>
print(instance.created_time) # <User: 小明>
# 序列化
data = us.dump(instance)
print(data)
return "hello"
if __name__ == '__main__':
app.run(debug=True,host="0.0.0.0",port=5999)
反序列化阶段对数据进行验证
基于内置验证器进行数据验证
内置验证器 | 描述 |
---|---|
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 datetime import datetime
from flask import Flask
from flask_marshmallow import Marshmallow
from marshmallow import Schema,fields,validate,post_dump,post_load,pre_dump,pre_load
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"]="mysql://root:123@127.0.0.1:3306/mofangapp?charset=utf8mb4"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy()
db.init_app(app)
ma = Marshmallow()
ma.init_app(app)
class User(db.Model):
__tablename__ = "tb_user"
id = db.Column(db.Integer, primary_key=True, comment="主键ID")
name = db.Column(db.String(255), index=True, comment="用户名")
email = db.String(db.String(255))
age = db.Column(db.Integer, comment="年龄")
password = db.Column(db.String(255), comment="登录密码")
mobile = db.Column(db.String(20), comment="手机号")
def __repr__(self):
return "<%s: %s>" % (self.__class__.__name__, self.name)
class UserSchema(Schema):
name = fields.String(validate=validate.Length(min=1))
age = fields.Integer(required=True,validate=validate.Range(min=16,max=100))
email = fields.String(validate=validate.Email())
password = fields.Str(load_only=True,validate=validate.Length(min=6,max=16)) # 相当于只写字段 "write-only"
mobile = fields.String(validate=validate.Regexp("^1[3-9]\d{9}$",error="手机号格式不正确!"))
@app.route("/")
def index():
user_data = {"email":"xiaoming@qq.com","name": "小明", "age": 20,"password":"123456","mobile":"13312345678"} # 报错
us = UserSchema()
# 反序列化
instance = us.load(user_data)
print(instance)
return "hello"
if __name__ == '__main__':
app.run(debug=True,host="0.0.0.0",port=5999)
自定义验证方法
通过context或者构造器实例对象进行参数传递
import random
from datetime import datetime
from flask import Flask
from flask_marshmallow import Marshmallow
from marshmallow import Schema,fields,validate,validates,validates_schema,ValidationError,post_load,pre_load
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"]="mysql://root:123@127.0.0.1:3306/mofangapp?charset=utf8mb4"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy()
db.init_app(app)
ma = Marshmallow()
ma.init_app(app)
class User(db.Model):
__tablename__ = "tb_user"
id = db.Column(db.Integer, primary_key=True, comment="主键ID")
name = db.Column(db.String(255), index=True, comment="用户名")
email = db.String(db.String(255))
age = db.Column(db.Integer, comment="年龄")
password = db.Column(db.String(255), comment="登录密码")
mobile = db.Column(db.String(20), comment="手机号")
def __repr__(self):
return "<%s: %s>" % (self.__class__.__name__, self.name)
class UserSchema(Schema):
name = fields.String()
age = fields.Integer()
email = fields.String()
password = fields.Str() # 密码
password2 = fields.String() # 确认密码
mobile = fields.String(validate=validate.Regexp("^1[3-9]\d{9}$",error="手机号格式不正确!"))
# 针对单个指定字段的值进行验证
@validates("mobile")
def validate_mobile(self,mobile):
if(mobile == "13312345678"):
raise ValidationError("手机号已经被注册!!")
return mobile
# 针对多个字段的验证
@validates_schema
def validate(self,data,**kwargs):
if(data["password"] != data["password2"]):
# 注意:验证失败以后,一定是raise抛出异常!!!不能是return!!!!
raise ValidationError(field_name="password2",message="密码和确认密码不一致!")
return data
@post_load
def post_load(self,data,**kwargs):
"""反序列化验证后的钩子方法"""
print("num=%s" % self.num)
print(self.context)
del data["password2"] # 删除掉不必要的字段
return User(**data)
@app.route("/")
def index():
user_data = {"email":"xiaoming@qq.com","name": "小明", "age": 20,"password":"123456","mobile":"13312345671","password2": "123456"}
num = random.randint(1,100)
# 如果将来在开发中有部分数据需要传递到构造器中进行调用,可以在实例化构造器时通过context传递参数进行,在构造器内部通过self.context调用
us = UserSchema(context={"num":num})
# 如果将来在开发中有部分数据需要传递到构造器中进行调用,可以作为构造器对象的属性进行传递
us.num = num
# 反序列化
instance = us.load(user_data)
print(instance)
return "hello"
if __name__ == '__main__':
app.run(debug=True,host="0.0.0.0",port=5999)
6. 模型构造器
官方文档:
- 注意:flask_marshmallow在0.12.0版本以后已经移除了ModelSchema和TableSchema这两个模型构造器类,官方转而推荐了使用SQLAlchemyAutoSchema和SQLAlchemySchema这2个类,前后两者用法类似。
- 模型构造器实际上是Schema的子类,所以前面所学习的自定义构造器字段,验证器,验证方法,钩子方法等等都可以写进来一起使用。
基于SQLAlchemySchema创建模型构造器
from flask import Flask
from flask_marshmallow import Marshmallow
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"]="mysql://root:123@127.0.0.1:3306/mofangapp?charset=utf8mb4"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy()
db.init_app(app)
ma = Marshmallow()
ma.init_app(app)
class User(db.Model):
__tablename__ = "tb_user"
id = db.Column(db.Integer, primary_key=True, comment="主键ID")
name = db.Column(db.String(255), nullable=False, index=True, comment="用户名")
email = db.String(db.String(255))
age = db.Column(db.Integer, comment="年龄")
password = db.Column(db.String(255), comment="登录密码")
mobile = db.Column(db.String(20), comment="手机号")
def __repr__(self):
return "<%s: %s>" % (self.__class__.__name__, self.name)
# 用法1:通过SQLAlchemySchema创建构造器,通过auto从模型中提取字段类型和选项
from marshmallow_sqlalchemy import SQLAlchemySchema,auto_field
from marshmallow import fields,validate
class UserSchema(SQLAlchemySchema):
"""模型构造器"""
id = auto_field()
name = auto_field()
password = auto_field()
# auto_field在使用过程中,除了可以复制模型对应字段的信息和数据类型以外,我们也可以增加补充说明
mobile = auto_field(required=True,validate=validate.Regexp("^1[3-9]\d{9}$"))
password2 = fields.String()
class Meta:
model = User # 模型类名 table = models.Album.__table__
load_instance = True # 反序列化阶段时,直接返回模型对象
include_relationships = True # 输出模型对象时同时对外键,是否也一并进行处理
include_fk = True # 序列化阶段是否也一并返回主键
@app.route("/")
def index():
user_data = {"name": "小明","mobile":"13"}
us = UserSchema()
instance = us.load(user_data,session=db.session)
print(instance)
return "hello"
if __name__ == '__main__':
with app.app_context():
db.drop_all()
db.create_all()
app.run(debug=True,host="0.0.0.0",port=5999)
基于SQLAlchemyAutoSchema创建模型构造器(常用)
class 构造器类名(SQLAlchemyAutoSchema):
class Meta:
model = 模型类名 # table = models.Album.__table__
include_relationships = True # 输出模型对象时同时对外键,是否也一并进行处理
include_fk = True # 序序列阶段是否也一并返回主键
load_instance = True # 反序列化阶段时,直接返回模型对象
sqla_session = db.session # 数据库连接会话对象
# fields= ["id","name"] # 启动的字段列表
exclude = ["id","name"] # 排除字段列表
案例
from flask import Flask
from flask_marshmallow import Marshmallow
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"]="mysql://root:123@127.0.0.1:3306/mofangapp?charset=utf8mb4"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy()
db.init_app(app)
ma = Marshmallow()
ma.init_app(app)
class User(db.Model):
__tablename__ = "tb_user"
id = db.Column(db.Integer, primary_key=True, comment="主键ID")
name = db.Column(db.String(255), nullable=False, index=True, comment="用户名")
email = db.String(db.String(255))
age = db.Column(db.Integer, comment="年龄")
password = db.Column(db.String(255), comment="登录密码")
mobile = db.Column(db.String(20), comment="手机号")
def __repr__(self):
return "<%s: %s>" % (self.__class__.__name__, self.name)
# 用法1:通过SQLAlchemySchema创建构造器,通过auto从模型中提取字段类型和选项
from marshmallow_sqlalchemy import SQLAlchemySchema,auto_field,SQLAlchemyAutoSchema
from marshmallow import fields,validate
class UserSchema(SQLAlchemyAutoSchema):
mobile = auto_field(required=True, validate=validate.Regexp("^1[3-9]\d{9}$"))
password2 = fields.String(required=True)
class Meta:
model = User # 模型类名 table = models.Album.__table__
load_instance = True # 反序列化阶段时,直接返回模型对象
include_relationships = True # 输出模型对象时同时对外键,是否也一并进行处理
include_fk = True # 序列化阶段是否也一并返回主键
sqla_session = db.session # 构造器操作数据库的会话对象
# fields = ["id","name","mobile","password2"] # 构造器启用的字段列表
exclude = ["id","name"] # 构造器禁用的字段列表
@app.route("/")
def index():
user_data = {"mobile":"13312341234","password2":"1234546"}
us = UserSchema()
instance = us.load(user_data)
print(instance)
return "hello"
if __name__ == '__main__':
with app.app_context():
db.drop_all()
db.create_all()
app.run(debug=True,host="0.0.0.0",port=5999)