前言

Flask-RESTX 提供了一种简单的方法来控制您在响应中实际呈现的数据或期望作为输入有效负载的数据。使用该fields模块,您可以在资源中使用所需的任何对象(ORM 模型/自定义类/等)。 fields还允许您格式化和过滤响应,因此您不必担心暴露内部数据结构。
在查看您的代码时,也非常清楚将呈现哪些数据以及将如何格式化。

基本用法

user模型

class Users(db.Model):__tablename__ = 'user'  # 数据库表名id = db.Column(db.Integer, primary_key=True, autoincrement=True)username = db.Column(db.String(50), unique=True, nullable=False)password = db.Column(db.String(128), nullable=False)is_active = db.Column(db.Boolean, default=1)email = db.Column(db.String(64), nullable=True)create_time = db.Column(db.DateTime, default=datetime.now)update_time = db.Column(db.DateTime, onupdate=datetime.now, default=datetime.now)def hash_password(self, password):"""密码加密"""self.password = sha256_crypt.encrypt(password)def verify_password(self, password):"""校验密码"""return sha256_crypt.verify(password, self.password)def __repr__(self):return f"<Users(id='{self.id}', username='{self.username}'...)>"

同步数据库后新增一条数据

自定义数据库对象 (User),该对象具有属性name、address和date_updated。对象上的任何其他属性都被视为私有属性,不会在输出中呈现。

from flask_restx import Resource, Api, reqparse, fieldsapi = Api(app)model = api.model('Model', {'username': fields.String,'email': fields.String,'create_time': fields.DateTime(dt_format='rfc822'),
})@api.route('/todo')
class Todo(Resource):@api.marshal_with(model, envelope='resource')def get(self, **kwargs):user = Users.query.get(1)      # 查询Users表数据return userif __name__ == '__main__':app.run(debug=True)

envelope='resource'关键字参数用来包装结果输出,返回结果示例

{"resource": {"username": "test","email": null,"create_time": "Mon, 05 Sep 2022 11:13:16 -0000"}
}

如果去掉envelope='resource'关键字参数,那么返回

{"username": "test","email": null,"create_time": "Mon, 05 Sep 2022 11:13:16 -0000"
}

装饰器marshal_with()实际上是获取您的数据对象并应用字段过滤。marshal_with()装饰器可以处理单个对象、字典或对象列表。

笔记:
marshal_with()是一个便利装饰器,在功能上等同于:class Todo(Resource):def get(self, **kwargs):return marshal(db_get_todo(), model), 200
@api.marshal_with装饰器添加了 swagger 的文档能力。

重命名属性

通常,您面向公众的字段名称与您的内部字段名称不同。要配置此映射,请使用attribute关键字参数。

model = api.model('Model', {'name': fields.String(attribute='username'),'email': fields.String,'create_time': fields.DateTime(dt_format='rfc822'),
})

那么会输出

{"resource": {"name": "test","email": null,"create_time": "Mon, 05 Sep 2022 11:13:16 -0000"}
}

lambda(或任何可调用的)也可以指定为attribute

model = {'name': fields.String(attribute=lambda x: x._private_name),'address': fields.String,
}

嵌套属性也可以通过以下方式访问attribute:

model = {'name': fields.String(attribute='people_list.0.person_dictionary.name'),'address': fields.String,
}

默认值

如果由于某种原因您的数据对象在字段列表中没有属性,您可以指定要返回的默认值而不是None.

model = {'name': fields.String(default='Anonymous User'),'address': fields.String,
}

自定义字段和多个值

有时您有自己的自定义格式需求。您可以子类化fields.Raw该类并实现格式功能。这在属性存储多条信息时特别有用。例如,一个位域,其各个位代表不同的值。您可以使用字段将单个属性多路复用到多个输出值。
此示例假定flags属性中的第 1 位表示“正常”或“紧急”项目,第 2 位表示“已读”或“未读”。这些项目可能很容易存储在位域中,但对于人类可读的输出,最好将它们转换为单独的字符串字段。

class UrgentItem(fields.Raw):def format(self, value):return "Urgent" if value & 0x01 else "Normal"class UnreadItem(fields.Raw):def format(self, value):return "Unread" if value & 0x02 else "Read"model = {'name': fields.String,'priority': UrgentItem(attribute='flags'),'status': UnreadItem(attribute='flags'),
}

网址和其他具体字段

Flask-RESTX 包含一个特殊字段 ,fields.Url它为所请求的资源合成一个 uri。这也是一个很好的例子,说明如何将数据添加到您的响应中,而这些数据实际上并不存在于您的数据对象中。

class RandomNumber(fields.Raw):def output(self, key, obj):return random.random()model = {'name': fields.String,# todo_resource is the endpoint name when you called api.route()'uri': fields.Url('todo_resource'),'random': RandomNumber,
}

默认情况下fields.Url返回一个相对 uri。要生成包含方案、主机名和端口的绝对 uri,请absolute=True在字段声明中传递关键字参数。要覆盖默认方案,请传递scheme关键字参数:

model = {'uri': fields.Url('todo_resource', absolute=True),'https_uri': fields.Url('todo_resource', absolute=True, scheme='https')
}

复杂结构

您可以拥有一个marshal()将转换为嵌套结构的平面结构:

>>> from flask_restx import fields, marshal
>>> import json
>>>
>>> resource_fields = {'name': fields.String}
>>> resource_fields['address'] = {}
>>> resource_fields['address']['line 1'] = fields.String(attribute='addr1')
>>> resource_fields['address']['line 2'] = fields.String(attribute='addr2')
>>> resource_fields['address']['city'] = fields.String
>>> resource_fields['address']['state'] = fields.String
>>> resource_fields['address']['zip'] = fields.String
>>> data = {'name': 'bob', 'addr1': '123 fake street', 'addr2': '', 'city': 'New York', 'state': 'NY', 'zip': '10468'}
>>> json.dumps(marshal(data, resource_fields))
'{"name": "bob", "address": {"line 1": "123 fake street", "line 2": "", "state": "NY", "zip": "10468", "city": "New York"}}'

笔记:地址字段实际上并不存在于数据对象上,但任何子字段都可以直接从对象访问属性,就好像它们没有嵌套一样。

列表字段

您还可以将字段解组为列表

>>> from flask_restx import fields, marshal
>>> import json
>>>
>>> resource_fields = {'name': fields.String, 'first_names': fields.List(fields.String)}
>>> data = {'name': 'Bougnazal', 'first_names' : ['Emile', 'Raoul']}
>>> json.dumps(marshal(data, resource_fields))
>>> '{"first_names": ["Emile", "Raoul"], "name": "Bougnazal"}'

通配符字段

如果您不知道要解组的字段的名称,可以使用Wildcard

>>> from flask_restx import fields, marshal
>>> import json
>>>
>>> wild = fields.Wildcard(fields.String)
>>> wildcard_fields = {'*': wild}
>>> data = {'John': 12, 'bob': 42, 'Jane': '68'}
>>> json.dumps(marshal(data, wildcard_fields))
>>> '{"Jane": "68", "bob": "42", "John": "12"}'

你给你的名字Wildcard就像一个真正的球体,如下所示

>>> from flask_restx import fields, marshal
>>> import json
>>>
>>> wild = fields.Wildcard(fields.String)
>>> wildcard_fields = {'j*': wild}
>>> data = {'John': 12, 'bob': 42, 'Jane': '68'}
>>> json.dumps(marshal(data, wildcard_fields))
>>> '{"Jane": "68", "John": "12"}'

笔记

重要的是你在你的模型之外定义你的模型(即你不能像这样使用它 :),因为它必须是有状态的,以跟踪它已经处理过的字段。Wildcard res_fields = {'*': fields.Wildcard(fields.String)}
glob 不是正则表达式,它只能处理简单的通配符,如 '*' 或 '?'。

为了避免出现意外行为,在Wildcard 与其他字段混合时,您可能希望使用 anOrderedDict并使用 the Wildcard作为最后一个字段

>>> from flask_restx import fields, marshal
>>> import json
>>>
>>> wild = fields.Wildcard(fields.Integer)
>>> # you can use it in api.model like this:
>>> # some_fields = api.model('MyModel', {'zoro': fields.String, '*': wild})
>>>
>>> data = {'John': 12, 'bob': 42, 'Jane': '68', 'zoro': 72}
>>> json.dumps(marshal(data, mod))
>>> '{"zoro": "72", "Jane": 68, "bob": 42, "John": 12}'

嵌套字段

虽然使用 dicts 嵌套字段可以将平面数据对象转换为嵌套响应,但您可以使用它Nested来解组嵌套数据结构并适当地呈现它们。

>>> from flask_restx import fields, marshal
>>> import json
>>>
>>> address_fields = {}
>>> address_fields['line 1'] = fields.String(attribute='addr1')
>>> address_fields['line 2'] = fields.String(attribute='addr2')
>>> address_fields['city'] = fields.String(attribute='city')
>>> address_fields['state'] = fields.String(attribute='state')
>>> address_fields['zip'] = fields.String(attribute='zip')
>>>
>>> resource_fields = {}
>>> resource_fields['name'] = fields.String
>>> resource_fields['billing_address'] = fields.Nested(address_fields)
>>> resource_fields['shipping_address'] = fields.Nested(address_fields)
>>> address1 = {'addr1': '123 fake street', 'city': 'New York', 'state': 'NY', 'zip': '10468'}
>>> address2 = {'addr1': '555 nowhere', 'city': 'New York', 'state': 'NY', 'zip': '10468'}
>>> data = {'name': 'bob', 'billing_address': address1, 'shipping_address': address2}
>>>
>>> json.dumps(marshal(data, resource_fields))
'{"billing_address": {"line 1": "123 fake street", "line 2": null, "state": "NY", "zip": "10468", "city": "New York"}, "name": "bob", "shipping_address": {"line 1": "555 nowhere", "line 2": null, "state": "NY", "zip": "10468", "city": "New York"}}'

此示例使用两个Nested字段。构造Nested函数需要一个字段字典来呈现为 sub-fields.input。构造函数和嵌套字典(上一个示例)之间的重要区别在于Nested属性的上下文。在此示例中, billing_address是一个具有自己的字段的复杂对象,并且传递给嵌套字段的上下文是子对象而不是原始data对象。换句话说: data.billing_address.addr1在这里是在范围内,而在前面的例子data.addr1中是位置属性。请记住:对象Nested为List属性创建了一个新范围。

默认情况下,当子对象为None时,将生成具有嵌套字段默认值的对象,而不是null。这可以通过传递allow_null参数来修改,Nested有关更多详细信息,请参阅构造函数。

使用NestedwithList来编组更复杂对象的列表:

user_fields = api.model('User', {'id': fields.Integer,'name': fields.String,
})user_list_fields = api.model('UserList', {'users': fields.List(fields.Nested(user_fields)),
})

Flask 学习-47.Flask-RESTX 自定义响应内容marshal_with相关推荐

  1. ASP.NET Core自定义响应内容

    问题 在业务开发中,对Web API的返回格式有一定要求,需要是定制化的Json结构,用于前端统一处理: {Status : 0,Message: "",Info : xxx } ...

  2. Flask学习之基础知识与功能

    一:flask的背景介绍 Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请 ...

  3. 后端框架flask学习小记

    1. 写在前面 最近在和几个伙伴尝试搭建一个新闻推荐系统, 算是一个推荐算法的实战项目, 里面涉及到了前后端交互, 该项目里面,使用了Flask作为后台框架, 为了理清楚整个系统的交互,所以就快速参考 ...

  4. Flask学习笔记总结(一)

    Flask学习笔记总结(一) 说明:开始在csdn上面记录一些关于自己学习技术的笔记总结. 文章目录 Flask学习笔记总结(一) 前言 一.python的web三大框架 二.flask入门 1.ws ...

  5. Python学习笔记——Flask模板

    目录 3.1 模板 3.2 过滤器: 3.3 Web表单: 3.4 控制语句 3.5 宏.继承.包含 3.6 Flask中的特殊变量和方法: 3.1 模板 在前面的示例中,视图函数的主要作用是生成请求 ...

  6. flask返回json数据到前端_小白学Flask第六天| abort函数、自定义错误方法、视图函数的返回值...

    点击蓝色字关注我们! 一个正在努力变强的公众号 本文内容: 1. abort函数的使用 2. 自定义错误处理方法 3. 设置响应信息的方法 4. 返回json数据的方法 abort函数的使用 abor ...

  7. Flask学习-Flask app接受第一个HTTP请求

    一.__call__() 在Flask app启动后,一旦uwsgi收到来自web server的请求,就会调用后端app,其实此时就是调用app的__call__(environ,start_res ...

  8. Flask学习笔记:错误处理

    1. 做好准备工作 进入项目主目录 激活虚拟环境 2. Flask中的错误处理 登陆账号,点开编辑资料页面,试着将用户名改为一个已经存在的用户名,然后,你会看到屏幕显示"Internal S ...

  9. python学习之Flask框架(二)

    request参数的使用 常用的request参数: 属性 说明 类型 values 记录请求的数据,并转换为字符串 * form 记录请求中的表单数据 MultiDict args 记录请求中的查询 ...

最新文章

  1. AnyHand——普通摄像头静态手势识别库
  2. 深入了解Oracle ASM(一):基础概念
  3. 高级java必须清楚的概念:原子性、可见性、有序性
  4. mysql backupadmin_如何使用 MySQL Administrator 管理/备份/还原 My SQL 数据库
  5. java 析构函数_《JAVA编程思想》5分钟速成:第5章(初始化和清理)
  6. linux动态链接库的创建
  7. 大数据系统架构包含哪些内容
  8. Adblock Plus无法屏蔽CSDN右下角广告解决
  9. MySQL查询当天、本周,本月,上一个月的数据
  10. QuickFlowDesigner教程(4)如何用代码控制活动操作人
  11. STM32的串口协议
  12. python执行bat文件_让Python文件也可以当bat文件运行
  13. win7计算机图标排列,win7文件夹内图标取消自动排列,取消自动排列
  14. 嵌入式系统的组成结构
  15. (Amazon)亚马逊GIF动态验证码识别,95识别率
  16. SpringBoot之模板引擎
  17. jsp+ssm计算机毕业设计宠物狗领养网站【附源码】
  18. OpenMP - 维基百科,自由的百科全书
  19. 初识计算机网络||物理层
  20. 学习ios(必看经典)牛人40天精通iOS开发的学习方法

热门文章

  1. Java,第二次作业——英里与千米的互换
  2. Qt实例:视频播放器
  3. 2020ICPC EC-Final D. City Brain
  4. DebeCMS环境搭建以及漏洞复现
  5. scala学习之路:1简单的打印输出,以及for循环的使用
  6. 使用C++实现简单的二维细胞自动机
  7. 腾讯的另一面:开放连接下的可持续社会价值创新践行者
  8. KDE桌面 SDDM 面板 桌面 KWIN美化日志
  9. ArcGIS应用(二十二)Arcmap加载激光雷达las格式数据
  10. php sql注入教程,SQL注入