前记
自己总结使用的,有错误之处欢迎之处。
觉得没用请直接退出,不必浪费您的时间私信骂没用。
- 一句话总结:
- ORM可以实现用python语句操作数据库,而不用写相应的sql语句。
- marshmallow可以将对应的数据(json形式)转换为python自己的数据类型从而存入生成的数据库中。
或者将数据库的内容转换为对应的json格式传输到前端。
marshmallow是什么?
- marshmallow是一个用来将复杂的orm对象与python原生数据类型之间相互转换的库。
- 简而言之,就是实现:
- object -> dict,
- object -> json string,
- object -> list,
- json string -> dict,
- json string -> list,
- json string -> object,
- dict -> object,
- list -> object。
ORM是什么?
- ORM(Object Relational Mapping)
- 对象——关系(数据库)之间的映射
- 可以通过简易的ORM框架的API进行数据库的操作。
- 即通过在python中操作对象从而实现对数据库进行操作。
- 定义一个对象,那就对应着一张表,这个对象的实例,就对应着表中的一条记录。
- 作用:
- 在关系型数据库和对象之间作一个映射,这样,我们在具体的操作数据库的时候,就不需要再去和复杂的SQL语句打交道,只要像平时操作对象一样操作它就可以了 。
- 说人话:通过ORM可以将写成的python代码自动转换成对应的sql语句并自动添加对应的字段。(参照对应的函数写相应的python代码)
- 写相应的python语句创造model的对象,然后第一次创建时会自动生成对应的SQL语句及字段(后续需要手动修改生成的内容)。
- 可以参考Object Relational Mapping(ORM)及python_flask_ORM用法写的很详细。
marshmallow中的序列化与反序列化
- 序列化:将数据对象转化为可存储或可传输的数据类型(例如json)
- dump()/dumps()
- 反序列化:将可存储或可传输的数据类型转化为数据对象
- load()/loads()
创建一个object作为基础
import datetime as dt
class User:
def __init__(self, name, email):
self.name = name
self.email = email
self.created_time = dt.datetime.now()
中间载体shema
- 数据结构之间的相互转换,需要有一个中间载体来实现,这个载体就是Schema类。
- 因此需要创建一个继承自Schema的UserSchema类,有两种方式创建。
- UserSchema类可以将User的属性名映射到Field对象。
# 定义一个类继承Schema
from marshmallow import Schema, fields
class UserSchema(Schema):
name = fields.Str()
email = fields.Email()
created_at = fields.DateTime()
# 使用Schema的from_dict()方法
from marshmallow import Schema, fields
UserSchema = Schema.from_dict(
{
"name": fields.Str(),
"email": fields.Email(),
"created_at": fields.DateTime()
}
)
简述Serializing(序列化对象)
- 即把自定义的对象转换为Python内置的对象(dict, str, list)。
- dump()方法:可以将一个object(对象)转换为一个dict(字典),示例如下:
user = User(name="TTY", email="tty@python.org")
schema = UserSchema()
res = schema.dump(user)
print(res)
# {'email': 'tty@python.org', 'name': 'TTY', 'created_time': '2019-08-05T14:43:51.168241+00:00'}
- dumps()方法:可以将一个object(对象)转换为一个str(json格式字符串),示例如下:
res2 = schema.dumps(user)
print(res2)
# '{"name": "TTY", "created_time": "2019-08-05T14:46:07.111755+00:00", "email": "tty@python.org"}'
序列化相关参数
- attribute
schema默认会序列化传入对象和自身定义的fields相同的属性, 然而你也会有需求使用不同的fields和属性名。
在这种情况下, 你需要明确定义这个fields将从什么属性名取值明确定义这个fields将从什么属性名取值。
下面代码中:UserSchema中的full_name,email_address,created_at分别从User对象的name,email,created_time属性取值。
class UserSchema(Schema):
full_name = fields.String(attribute="name")
email_address = fields.Email(attribute="email")
created_at = fields.DateTime(attribute="created_time")
- dump_only——等同于只读字段。
# created_at is "read-only"
created_at = fields.DateTime(dump_only=True)
- default——输入值缺失用default指定默认值
class UserSchema(Schema):
birthdate = fields.DateTime(default=dt.datetime(2020, 9, 9))
简述Deserializing(反序列化)
- 反序列化是将Python内置的对象转换为自定义的对象。
- load()方法:它将输入的字典格式数据转换成应用层数据结构。他也能起到验证输入的字典格式数据的作用。默认情况下,load()方法返回一个字典,当输入的数据的值不匹配字段类型时,抛出 ValidationError 异常。
schema = UserSchema()
res = schema.load(user_data)
print(res)
# {'email': 'tty2@python.org', 'created_time': datetime.datetime(2019, 8, 5, 14, 46, 7), 'name': 'tty2'}
- loads()方法:可将json字符串转换为dict
user_json = '{ "created_at": "2014-08-11T05:26:03.869245", "email": "ken@yahoo.com", "name": "Ken" }'
schema = UserSchema()
j2d = schema.loads(user_json) # 此处传入的是一个json字符串,返回的一个字典
print('j2d:', type(j2d), j2d)
# 输出结果如下:
j2d: <class 'dict'> {'created_at': datetime.datetime(2021, 2, 26, 14, 46, 15, 787833), 'name': 'Monty', 'email': 'monty@python.org'}
反序列化参数
- load_from
Schema默认反序列化传入字典和输出字典中相同的字段名。
如果你觉得数据不匹配你的schema, 可以传入load_from参数指定需要增加load的字段名。
(原字段名也能load, 且优先load原字段名)
class UserSchema(Schema):
full_name = fields.String(load_from="name")
email_address = fields.Email(load_from="email")
created_at = fields.DateTime(load_from="created_time")
- load_only——等同于只写字段。
# password is "write-only"
password = fields.Str(load_only=True)
- missing——输入值缺失用missing指定默认值。
class UserSchema(Schema):
id = fields.UUID(missing=uuid.uuid1)
通用参数
-
many = True——处理多个对象的集合
- 多个对象的集合如果是可迭代的,那么也可以直接对这个集合进行序列化或者反序列化。在实例化Scheme类时设置参数many=True
- 也可以不在实例化类的时候设置,而在调用dump()方法的时候传入这个参数。
user1 = User(name="tty1", email="tty1@python.org")
user2 = User(name="tty2", email="tty2@python.org")
users = [user1, user2]
# 第一种方法
schema = UserSchema(many=True)
res = schema.dump(users)
# 第二种方法
# schema = UserSchema()
# res = schema.dump(users, many=True)
print(res)
# [{'created_time': '2019-08-05T15:09:19.781325+00:00', 'email': 'tty1@python.org', 'name': 'tty1'},
# {'created_time': '2019-08-05T15:09:19.781325+00:00', 'email': 'tty2@python.org', 'name': 'tty2'}]
- data_key——让key同时满足序列化与反序列化的方法
class UserSchema(Schema):
full_name = fields.String(data_key="name")
email_address = fields.Email(data_key="email")
created_at = fields.DateTime(data_key="created_time")
必填字段校验——required=True
- 必填字段的校验,可通过传入关键字参数required=True ,可以自定义缺失字段时抛出的异常信息:设置参数error_messages的值,示例:
from marshmallow import Schema, fields, ValidationError
class UserSchema(Schema):
name = fields.String(required=True)
age = fields.Integer(
required=True,
error_messages={"required": "Age is required."})
city = fields.String(
required=True,
error_messages={"required": {"message": "City required", "code": 400}},
)
email = fields.Email()
try:
result = UserSchema().load({"email": "foo@bar.com"})
except ValidationError as err:
print(err.messages)
# {'age': ['Age is required.'],
# 'city': {'code': 400, 'message': 'City required'},
# 'name': ['Missing data for required field.']}
忽略部分字段——partial
- 使用required之后我们还是可以在传入数据的时候忽略这个必填字段。
- 只想校验部分的字段,可以通过传递partial参数来指定需要校验的字段,示例:
class UserSchema(Schema):
name = fields.String(required=True)
age = fields.Integer(required=True)
# 方法一:在load()方法设置partial参数的值(元组),表时忽略那些字段。
schema = UserSchema()
res = schema.load({"age": 42}, partial=("name",))
print(res)
# {'age': 42}
# 方法二:直接设置partial=True
schema = UserSchema()
res = schema.load({"age": 42}, partial=True)
print(res)
# {'age': 42}
参考文献
什么是ORM
Object Relational Mapping(ORM)
python_flask_ORM——用法很详细
python之Marshmallow
Marshmallow快速上手及参数校验