python3 marshmallow学习

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

安装:

pip install -U marshmallow

Object -> dict

1 简单的例子
from marshmallow import Schema, fields

class UserSchema(Schema):
name = fields.String()
email = fields.Email()
age = fields.Integer()
create_at = fields.DateTime(dump_only=True) class User:
def __init__(self, *, name, email, age):
self.name = name
self.email = email
self.age = age zhuyu = User(name="朱宇", email="33333@qq.com", age=22)
user_schema = UserSchema()
result = user_schema.dump(zhuyu, many=False)
print(result,isinstance(result, dict))
# {'age': 22, 'name': '朱宇', 'email': '33333@qq.com'} True
result = user_schema.dumps(zhuyu, many=False)
print(result,isinstance(result, str))
# {"age": 22, "name": "\u6731\u5b87", "email": "33333@qq.com"} True

这是一个将类转化为字典或者json格式的字典的例子,使用UserSchema实例的dump转为字典格式,dumps方法转为json格式的字符串。

这种就很像django中的序列化了。通过orm查询到的数据,转为字典格式数据,通过json进行前后台数据传输。

从上面这个例子中,我们的User对象并没有create_at这个对象,通过UserSchema的对象调用dump,得到的数据中也没有create_at这个数据。dump这个方法,对传入的参数的属性的规定不是很严格,只会对UserSchema存在的属性和User存在的属性进行操作。属性名必须要相同。

2 使用only,exclude的使用

对于上面的例子,假如有个需求,不需要看到user的age属性。

zhuyu = User(name="朱宇", email="33333@qq.com", age=22)
user_schema = UserSchema(only=("name", "email"))
result = user_schema.dump(zhuyu, many=False)
print(result)
# {'name': '朱宇', 'email': '33333@qq.com'}
user_schema = UserSchema(exclude=("age",))
result = user_schema.dump(zhuyu, many=False)
print(result)
# {'name': '朱宇', 'email': '33333@qq.com'}

3 fields.Nested的使用

就拿orm来说,两个model类型,很有可能存在一对一,一对多,多对多的关系,那么怎么进行序列化呢?

关于Nested具体使用:https://marshmallow.readthedocs.io/en/stable/nesting.html

from marshmallow import Schema, fields

class User:
def __init__(self, name, pwd, email):
self.name = name
self.pwd = pwd
self.email = email class Blog:
def __init__(self, title, author: User):
self.title = title
self.author = author class UserSchema(Schema):
name = fields.Str()
pwd = fields.Str()
email = fields.Email() class BlogSchema(Schema):
title = fields.Str()
author = fields.Nested(UserSchema) zhuyu = User(name="朱宇", pwd="123456", email="33333@qq.com")
blog = Blog(title="朱宇的博客", author=zhuyu) user_schema = UserSchema()
result = user_schema.dump(zhuyu, many=False)
print(result)
# {'email': '33333@qq.com', 'name': '朱宇', 'pwd': '123456'}
blog_schema = BlogSchema()
result = blog_schema.dump(blog, many=False)
print(result)
# {'author': {'email': '33333@qq.com', 'name': '朱宇', 'pwd': '123456'}, 'title': '朱宇的博客'}

validate对数据校验

在我们写web的时候,经常会接受到携带参数的请求。我们通过这个携带的参数,完成相应的业务逻辑。但是服务器不能知道该请求是从哪种方式过来,携带的参数就会很多种,所以我们不能对前台传来的参数百分百信任,必须做参数校验。

当然对前台参数进行校验的包有很多,这里就说marshmallow

from marshmallow import Schema, fields, pprint
import datetime as dt class UserSchema(Schema):
name = fields.Str()
email = fields.Email() user_dict = {
"name": "朱宇",
"email": "3333333.com",
}
user_schema = UserSchema()
result = user_schema.validate(data=user_dict)
pprint(result)
# {'email': ['Not a valid email address.']}

调用UserSchema实例的validate方法,参数为字典格式的数据,返回值就是一个字典类型。如果参数符合校验规则的话,那么返回的就是一个空字典,不符合的话,返回的就是key为字段名,value为错误信息。上面这个例子,说email这个字段不是一个合法的邮箱地址。fields.Email它会有一套默认的校验规则,我们阔以通过validate这个关键参数,定义自己需要的验证规则。

validate关键字参数
from marshmallow import Schema, fields, validate, pprint
from hashlib import md5 class UserSchema(Schema):
# 用户名为字符串,最短为2位,最长为8位
name = fields.String(validate=validate.Length(min=2, max=8, error="用户名长度2-8位"))
# 密码必须为32位字符串,这里我们使用md5加密
password = fields.String(validate=validate.Length(equal=32, error="密码长度必须为32位"))
# 年龄是14岁到77岁之间
age = fields.Integer(validate=validate.Range(14, 77, error="必须为14-77之间"))
# 性别必须是男,女,其他中的一个
grade = fields.String(validate=validate.OneOf(choices=("男", "女", "其他"), error="必须为男,女,其他三个中的一个"))
#
email = fields.String(validate=validate.Email(error="邮箱格式错误")) error_user_dict = {
"name": "朱",
"password": "333444",
"age": 13,
"grade": "不清楚",
"email": "3333.com"
}
user_schema = UserSchema()
result = user_schema.validate(data=error_user_dict, many=False)
pprint(result)
# {'age': ['必须为14-77之间'],
# 'email': ['邮箱格式错误'],
# 'grade': ['必须为男,女,其他三个中的一个'],
# 'name': ['用户名长度2-8位'],
# 'password': ['密码长度必须为32位']} user_dict = {
"name": "朱春雨",
"password": md5(bytes("1", encoding="utf-8")).hexdigest(),
"age": 22,
"grade": "男",
"email": "333444@qq.com"
}
result = user_schema.validate(data=user_dict, many=False)
pprint(result)
# {}

关于validate这个模块下还有其他的校验规则,具体可以去源码当中看。

除了本身提供的校验方法之外,我们同样可以自定义校验规则

# name = fields.String(validate=validate.Length(min=2, max=8, error="用户名长度2-8位"))

这是我们上面代码中,name字段的校验方法,validate的值为Length对象的实例,当要对name这个字段进行校验时,会将name对应的值会这样执行:validate.Length(min=2, max=8, error="用户名长度2-8位")(name的值),那么这样的话,就会调用Length对象里的__call__方法,将name的值传入。我们也可以这样去写自己的校验方法。大致的意思是validate=值,这个值他是可调用的,也就是有__call__方法。

# 方法一:类的方式
import typing
from marshmallow import Schema, fields, validate, ValidationError, pprint class CustomizeVal(validate.Validator): def __init__(self, *, word: str, error: str = None):
self.word = word
self.error = error or "不能已什么开头{}".format(self.word) def __call__(self, value: str, *args, **kwargs) -> typing.Any:
if value.startswith(self.word):
raise ValidationError(self.error) return value class TestSchema(Schema):
name = fields.String(validate=CustomizeVal(word="SB")) error_test_dict = {
"name": "SB_SBSBBSBS"
}
test_schema = TestSchema()
res = test_schema.validate(data=error_test_dict, many=False)
pprint(res)
# 'name': ['不能已什么开头SB']}
test_dict = {
"name": "朱宇"
}
res = test_schema.validate(data=test_dict, many=False)
pprint(res)
# {} # 方法二:函数的方法
def func_val(value: str) -> typing.Any:
"""定义不能以SB结尾的校验规则"""
if value.endswith("SB"):
raise ValidationError("不能以SB结尾")
return value class Test2Schema(Schema):
name = fields.String(validate=func_val) error_test_dict = {
"name": "朱宇_SB"
}
test_2_schema = Test2Schema()
res = test_2_schema.validate(data=error_test_dict,many=False)
pprint(res)
# {'name': ['不能以SB结尾']}

dict -> Object

1 简单的例子
from marshmallow import Schema, fields
import json class User:
def __init__(self, name, password):
self.name = name
self.password = password class UserSchema(Schema):
name = fields.String()
password = fields.String() user_dict = {
"name": "朱宇",
"password": "123"
}
user_dict_json = json.dumps(user_dict)
user_schema = UserSchema()
res = user_schema.load(data=user_dict, many=False)
print(res, isinstance(res, dict))
# {'password': '123', 'name': '朱宇'} True
res = user_schema.loads(user_dict_json, many=False)
print(res, isinstance(res, dict))
# {'password': '123', 'name': '朱宇'} True

调用load或者loads方法,它也会进行校验,但是一旦校验失败了,就会抛异常,且不会捕捉。所以一般的话,还是先调用validate方法进行校验,检验无误的话,再进行load方法调用。上面的例子中变量res的类型为dict。如果想要res的类型变为User类型呢?

from marshmallow import Schema, fields, post_load

class User:
def __init__(self, name, password):
self.name = name
self.password = password def __repr__(self):
return "<User-{}>".format(self.name) class UserSchema(Schema):
name = fields.String()
password = fields.String() @post_load
def make_user(self, data, **kwargs):
return User(**data) user_dict = {
"name": "朱宇",
"password": "123"
}
user_schema = UserSchema()
res = user_schema.load(data=user_dict, many=False)
print(res, isinstance(res, User))
# <User-朱宇> True

知识整理就写到这里。

最好是去看marshmallow的官方文档:https://marshmallow.readthedocs.io/en/stable/

python3 marshmallow学习的更多相关文章

  1. python3.4学习笔记(十七) 网络爬虫使用Beautifulsoup4抓取内容

    python3.4学习笔记(十七) 网络爬虫使用Beautifulsoup4抓取内容 Beautiful Soup 是用Python写的一个HTML/XML的解析器,它可以很好的处理不规范标记并生成剖 ...

  2. python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息,抓取政府网新闻内容

    python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息PySpider:一个国人编写的强大的网络爬虫系统并带有强大的WebUI,采用Python语言编写 ...

  3. python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例

    python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例 新浪爱彩双色球开奖数据URL:http://zst.aicai.com/ssq/openInfo/ 最终输出结果格 ...

  4. python3.4学习笔记(十八) pycharm 安装使用、注册码、显示行号和字体大小等常用设置

    python3.4学习笔记(十八) pycharm 安装使用.注册码.显示行号和字体大小等常用设置Download JetBrains Python IDE :: PyCharmhttp://www. ...

  5. python3.4学习笔记(二十六) Python 输出json到文件,让json.dumps输出中文 实例代码

    python3.4学习笔记(二十六) Python 输出json到文件,让json.dumps输出中文 实例代码 python的json.dumps方法默认会输出成这种格式"\u535a\u ...

  6. python3.4学习笔记(二十五) Python 调用mysql redis实例代码

    python3.4学习笔记(二十五) Python 调用mysql redis实例代码 #coding: utf-8 __author__ = 'zdz8207' #python2.7 import ...

  7. python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法

    python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法window安装redis,下载Redis的压缩包https://git ...

  8. python3.4学习笔记(二十三) Python调用淘宝IP库获取IP归属地返回省市运营商实例代码

    python3.4学习笔记(二十三) Python调用淘宝IP库获取IP归属地返回省市运营商实例代码 淘宝IP地址库 http://ip.taobao.com/目前提供的服务包括:1. 根据用户提供的 ...

  9. python3.4学习笔记(二十二) python 在字符串里面插入指定分割符,将list中的字符转为数字

    python3.4学习笔记(二十二) python 在字符串里面插入指定分割符,将list中的字符转为数字在字符串里面插入指定分割符的方法,先把字符串变成list然后用join方法变成字符串str=' ...

随机推荐

  1. 让Linux中的Nginx支持中文文件名

    原文:https://blog.csdn.net/soeben/article/details/79525964 首先你的服务器需要安装了UTF-8字符集在命令行里输入env|grep LANG如果显 ...

  2. asp.net core mvc基于Redis实现分布式锁,C# WebApi接口防止高并发重复请求,分布式锁的接口幂等性实现

    使用背景:在使用app或者pc网页时,可能由于网络原因,api接口可能被前端调用一个接口重复2次的情况,但是请求内容是一样的.这样在同一个短暂的时间内,就会有两个相同请求,而程序只希望处理第一个请求, ...

  3. 2-剑指offer: 最小的K个数

    题目描述 输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,. 代码: // 这种topN问题比较常见的是使用堆来解决,最小的k个 ...

  4. 使用SpringBoot编写Restful风格接口

    一.简介    Restful是一种对url进行规范的编码风格,通常一个网址对应一个资源,访问形式类似http://xxx.com/xx/{id}/{id}. 举个栗子,当我们在某购物网站上买手机时会 ...

  5. VS 编译总是出现错误: "LC.EXE 已退出,代码为-1"

    最近在开发CS的一个项目时,编译总是出现错误: "LC.EXE 已退出,代码为-1" 解决方法一:用记事本打开*.licx,里面写的全是第三方插件的指定DLL,删除错误信息,保存, ...

  6. SpringBoot如何切换Redis默认库

    一些闲扯的话 我们清楚,Redis 尽管提供了 16 个索引库,但是每个数据库之间是隔离互不共享的,客户端默认连接使用的是 0 号数据库 . 注意:上方情况是基于单机 Redis 的,在集群模式下是没 ...

  7. cc2530的第三次实验,按键中断控制流水灯

    cc2530的第三次实验:按键中断控制流水灯 效果为按一次按键,流水灯亮一次 实验相关电路图: 实验相关寄存器: 初始化函数 //初始化LED灯 //设置P1SEL,通用为0,外设为1 1111110 ...

  8. 获取DOM元素的方式有哪些

    document.getElementById();//id名 document.getElementsByTagName();//标签名 document.getElementsByClassNam ...

  9. Android 从零编写一个带标签 TagTextView

    最近公司的项目升级到了 9.x,随之而来的就是一大波的更新,其中有个比较明显的改变就是很多板块都出了一个带标签的设计图,如下: 怎么实现 看到这个,大多数小伙伴都能想到这就是一个简单的图文混排,不由得 ...

  10. 调用 Dll 中的函数时,出现栈(STACK)的清除问题 -> 故障模块名称: StackHash_0a9e

    在一个名为 test.dll 文件中,有一个 Max() 函数的定义是: #ifdef BUILD_DLL #define DLL_EXPORT __declspec(dllexport) __std ...