来源:GINO 官方文档
本文约4810字,建议阅读14分钟。
本文先容GitHub 千星项目 GINO——可以既方便快捷、又大略明了地访问数据库。

随着 Tornado[1] 和 asyncio[2] 等框架的陆续呈现,Python 异步编程这个话题也在逐渐升温。在这个烧脑的异步天下里,有没有办法可以既方便快捷、又大略明了地访问数据库呢?GitHub 千星项目 GINO 理解一下!
1. GINO 是谁
GINO 是一个“轻量级”异步 ORM 框架,它的全称是 GINO Is Not ORM,借鉴了 GNU is Not Unix 的递归定义[3] 手腕。以是,GINO 一定要全!
部!
大!
写!
如果像这样“Gino”就变成了人名,你肯定要问一句“这是谁”。
ORM,即关系工具映射(Object-Relational Mapping[4]),是一类开拓职员喜闻乐见的效率工具,它们"极大地"提升了写代码的幸福指数。GINO 是用来访问数据库的,也供应了工具映射的工具,那为什么非说 GINO 不是 ORM 呢?
由于物极必反,ORM 在带来生活便利的同时,也是 bug 成长的温床 —— 传统 ORM 每每会选择捐躯明确性(explicitness)来换取便捷性(convenience),再加上 Python 得天独厚的灵巧性(flexibility),创造出了一种爆炸式的化学反应。一旦代码初具规模,项目或多或少都会碰着 ORM 反噬的情景:性能莫名其妙的差、出问题找不到缘故原由、为了鸡毛蒜皮的小事大动兵戈。随便一句 current_user.name 都有可能触发一大堆意想不到的数据库调用,这代码你让我怎么调试?
传统 ORM 的学习曲线前平后陡,能在快速原型开拓中大展技艺,但运用到大型项目中却十分磨练开拓职员的均匀水平。
所有这些问题如果再放进异步编程的环境里,那便是 O(n2) 的繁芜度了 —— 哦不,是 O(2n)。这对付一款精良的异步 ORM 框架来说是不可接管的,以是 GINO 是 ORM 但不是一个传统的 ORM,正犹如 GNU 不是一个传统的 Unix 一样,形似而神不似。
以是在 2017 年创作之初,我就给 GINO 定下了两个古迹目标:1) 方便快捷,2) 大略明了。三年后的本日,我索性在 1.0 稳定版发布的前夕做个年终总结。
2. 先说"方便快捷""方便快捷"紧张说的是开拓效率。
重视开拓效率的观点对付写 Python 的同学来说可能并不陌生,某些场景下,开拓职员的韶光确实比机器的韶光值钱。以是,传统 ORM 里的工具映射不能丢。
from gino import Ginodb = Gino()class User(db.Model): __tablename__ = "users" id = db.Column(db.Integer, primary_key=True)name=db.Column(db.String)
这么定义表构造乃至让人有点小愉快。咦,为什么这么眼熟?
没有错,这便是 SQLAlchemy ORM[5] 的定义风格。GINO 并不是从头造轮子,而是在 SQLAlchemy core[6](SQLAlchemy 中卖力构建 SQL 的底层核心)的根本上开拓的。这么做除了能保持熟习的味道(以节省学习和迁移本钱),更主要的是带来了全体 SQLAlchemy 的生态环境:开箱即用的数据库变更管理工具 Alembic[7]、各种 SQLAlchemy 的增强插件[8]、专业领域的 PostGIS/geoalchemy[9] 等,GINO 全都兼容。
是不是十分方便、十分快捷?不止这样。
GINO 一站式地办理了常用 CRUD 快捷办法[10]、高下文管理(aiocontextvars[11][12])、数据库事务封装和嵌套[13]、连接池管理和
daisy = await User.create(name="daisy")awaitdaisy.update(name="Daisy").apply()
GINO 还供应了[15] 各大盛行异步 Web 框架的定制版插件,能叫上名字的像 Tornado[1]、aiohttp[16]、Sanic[17]、FastAPI[18]/Starlette[19]、Quart[20] 什么的都有,从大略示范莅临盆环境的各种例子品种完好,妈妈再也不用担心我不汇合成 Web 框架了。
为了让不同运用处景下的用户体验到最大的善意,GINO 目前支持三种不同程度的用法,成功实现了对同期竞品 asyncpgsa[21] 的降维打击:
最少侵入型[22]:SQLAlchemy core 原教旨主义者,只有异步实行时才用到 GINO。终生不婚型[23]:天生厌恶"工具",只愿定义"表",空手接 SQL。火力全开型[24]:最大程度的便利,非范例异步 ORM。末了,虽然是 Python(绝不是黑哈),但 GINO 在实行效率上也没落下。基于 MagicStack 出品必属佳构的、一秒可读百万行的 asyncpg[25],以及 uvloop[26](可选)的强力加持,GINO 跑起来也是可以飞快的,被广泛运用于诸如实时汇率、谈天机器人、在线游戏等高并发领域,深受俄罗斯和乌克兰公民的爱戴。
3. 再说"大略明了"Explicit is better than implicit.
Simple is better than complex.
-- The Zen of Python, PEP 20[27]
Python 之禅完美表达了 GINO 的态度 —— 明确性(explicitness)对付上了规模的异步工程项目来说尤为主要,因此 GINO 的很多设计都受到了明确性的影响。
比如说,GINO 的 Model 是完备无状态的普通 Python 工具(POPO[28])—— 例如前面的 User 类,它的实例
daisy 便是内存里面的常规工具,你可以用 daisy.name 访问属性,也可以用 daisy.name = "DAISY" 来修正属性,或者用 u = User() 来创建新的实例,这些操作都不会访问数据库,绝对绿色环保无毒副浸染。
等到须要操作数据库的时候,你一定会有感知的。比如实行 INSERT 要用 u = await User.create(),而 UPDATE 则是 await u.update(name="Daisy").apply()。
个中, u.update(name="Daisy") 与 u.name = "Daisy" 类似,都是只在内存里修正工具的属性,不同的是 u.update() 还会返回一个包含本次变更的中间结果,对其实行 await xxx.apply() 则会将这些变更运用到数据库里。
这里的 await 便是明确性的关键,意味着我们要跳出去实行数据库操作了。换句话说,没有 await 就没有数据库操作。
另一方面,对付如何将数据库查询结果组装成内存工具及其属性,GINO 也有一套精妙的显式机制 —— 可定制化的加载器 loaders[29]。对付大略直不雅观的一对一加载,GINO 自然是奉养到家的,比如用 u = await User.get(1) 可以直接获取到 ID 为 1 的用户工具。但是对付更繁芜的查询,GINO 不会去无端预测主人的意图,而全权交给用户来明确地定义。加载器的用法也是很大略的,比如一个用户可能写了很多本书:
class Book(db.Model): __tablename__ = "books" id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String)author_id=db.ForeignKey("users.id")
然后这样来加载这种多对一关系,以同时获取所有的书和他们的作者:
query = Book.outerjoin(User).select()loader = Book.load(author=User)async for book in query.gino.load(loader).iterate():print(book.title,"writtenby",book.author.name)
很大略的一个外连接查询 Book.outerjoin(User),合营一个直不雅观的加载器 Book.load(author=User),就实现了:
实行 SELECT FROM books LEFT JOIN users ON ...;将数据库返回结果的每一行中,属于 books 的字段加载成一个 Book 实例;然后将该行中剩下的属于 users 的字段加载成一个 User 实例;末了将 User 实例设置到 Book 实例的 author 属性上。既大略又明了有没有!
你乃至可以手写任何 SQL,然后定制加载器自动加载成期望的工具关系,精准掌握加载行为,指哪儿打哪儿。GINO 还有很多类似的特性,在这里就不一一列举了。
随着这几年 GINO 不断演进成熟,Python 开源社区里也相继涌现了像 Tortoise ORM[30]、ORM[31](是的,这个项目就叫 ORM......我真 ORZ。出品方是 Encode,Starlette 便是他们的作品)等精良的异步 ORM 框架。它们关注的重点与 GINO 稍有不同,但都是同行就不多评价了。
GINO 的最大上风还是在于充分平衡了开拓效率和明确性之间的辩证抵牾关系,用 GINO 开拓运用程序的时候不用担心会被猜想之外的行为所惊吓到,同时也不须要为这种明确性付出过大的工程代价,上手后依然可以快速、快乐地编程。同时,大量的成功案例也证明了 GINO 已经初步具备发布 1.0 稳定版的各种条件,可以谨慎地用于生产环境了。
以下是比来统计到的关于 GINO 的运用案例:
笔者事情上开拓的一个做事:https://github.com/uc-cdis/metadata-service还是笔者自己写的一个工具:https://github.com/fantix/aintq一个汇率 API 做事:https://exchangeratesapi.io/各种 Telegram、Discord 的 Bot。ArchLinux 用户包:https://aur.archlinux.org/packages/python-gino/https://github.com/bryanforbes/gino-stubs/俄语教程:https://www.youtube.com/watch?v=WW4rOnfhiQY高性能模板项目:https://github.com/leosussan/fastapi-gino-arq-uvicorn还有几个商用的,但没征得赞许就不贴出来了。其余,GINO 还知心肠供应了中文文档[32],从上手教程到事理解释搜罗万象(虽然文档还在努力编写中!
):
GINO 目前的不敷之处还有一些,比如没有照顾到 Python 3 的类型提示,因此还不能完备发挥 IDE 的潜能(上面那个 gino-stubs 便是有人受不明晰自己写了一个类型表明)。MySQL 目前也是不支持的,但 GINO 从比较早就解耦了不同 SQL 方言和驱动的集成,以是这些功能会陆续在 1.1 和 1.2 版本中跟上。
5. 培植社会主义GINO 是一个开源项目,以是欢迎大家一起来培植!
目前急需帮助的有:
各个 Web 框架插件的掩护事情须要多人认领;更多的例子和文档,以及中文、俄文的翻译;MySQL 的支持。以及下面这些一贯须要的帮助:
用 GINO,找 bug,提建议;修 bug,做功能,提 PR;掩护社区,回答问题,参与谈论;末了也是最主要的:去 GitHub 上给 GINO 加一颗星星!6. 关于作者
I'm a software architect, fan of coding for over 20 years, and now focusing on software engineering, high concurrency and development performance. Python is my chief language, and I worked on Linux for 10 years, managing development teams up to 20 people for 8 years. Big fan of open source, created project GINO with 1000+ GitHub stars.
OPEN SOURCE
Python / 2018-2019
I started to contribute to Python programming language with MagicStack fellows, focusing on the asyncio library.
GINO / 2017-2019
GINO is an ORM library for Python asyncio. It is an integration of SQLAlchemy core and asyncpg.
aioh2 / 2016
This is an integration of an HTTP/2 protocol library and Python 3 asyncio.
tulipcore / 2015
I've implemented the most part of the event loop core of Gevent with pure Python 3 asyncio (tulip) code.
zmq.rs / 2014
It was my attempt to implement the ZeroMQ stack in pure Rust.
ArchLinux / 2013 - 2016
I maintained the packages of a dozen of build toolchains and base libraries of ArchLinux for x32-ABI, e.g. GCC, glibc, openssl, curl, util-linux, etc.
Gevent / 2011 - 2013
I contributed the initial port of Gevent to Python 3, which was later merged into Gevent 1.1 by its new maintainer. I've also ported Greenlet to x32-ABI.
Translations / 2008 - 2015
I was involved/started several translation projects, e.g. Ubuntu, libexif, Twisted, Python-beginners, ZeroMQ, etc.
87 年生人,6 岁开始打仗编程,二十五六年的编程史和十三四年的事情履历教会了我许多软件开拓的奥义。小时候写 GBasic、QBasic 和 Visual Basic;大学里开始写 Java 并打仗到了 FreeBSD 和 Ubuntu 等开源项目且一发不可整顿;事情头五年转向了 Python,通过 Twisted 和 Eventlet 等项目理解了异步编程,期间贡献了 Gevent 的 Python 3 迁移;也曾在创业的潮流中留下身影,亲自经历并见证了软件技能随着手游、新媒体、矿圈、互金、电商、社交、文娱、汽车等行业的起起伏伏;目前在芝大连续做生物大数据干系的开源项目。业余韶光除了开拓掩护 GINO 项目外,还会偶尔修一修 uvloop、asyncpg 和 CPython 的 bug :P
7.参考文献[1] Facebook. Tornado.
URL: https://zh.wikipedia.org/wiki/Tornado.
[2] Python Software Foundation. asyncio — 异步 I/O.
URL: https://docs.python.org/zh-cn/3/library/asyncio.html.
[3] 维基百科. GNU.
URL: https://zh.wikipedia.org/wiki/GNU.
[4] 维基百科. 工具关系映射.
URL: https://zh.wikipedia.org/wiki/工具关系映射
[5] 维基百科. SQLAlchemy.
URL: https://zh.wikipedia.org/wiki/SQLAlchemy.
[6] Michael Bayer. SQLAlchemy Core - SQLAlchemy . Documentation.
URL: https://docs.sqlalchemy.org/en/13/core/index.html.
[7] Michael Bayer. Welcome to Alembic’s documentation!
URL: https://alembic.sqlalchemy.org/en/latest/.
[8] Hong Minhee. A curated list of awesome tools for SQLAlchemy.
URL: https://github.com/dahlia/awesome-sqlalchemy.
[9] Does it have postgis support? Does it have postgis support?
URL: https://github.com/python-gino/gino/issues/627.
[10] Fantix King. GINO 根本教程 - 增编削查.
URL: https://python-gino.org/docs/zh/master/tutorials/tutorial.html#crud-operations.
[11] Python Software Foundation. contextvars —Context Variables.
URL: https://docs.python.org/3/library/contextvars.html.
[12] Fantix King. gino/aiocontextvars.py.
URL: https://github.com/python-gino/gino/blob/f2c273a43a3ed893a767d4239046f2befabf510d/src/gino/aiocontextvars.py.
[13] Fantix King. 数据库事务.
URL: https://python-gino.org/docs/zh/master/how-to/transaction.html.
[14] Fantix King. 引擎与连接.
URL: https://python-gino.org/docs/zh/master/explanation/engine.html.
[15] GINO Community. GINO Community.
URL: https://github.com/python-gino/.
[16] aiohttp maintainers. Welcome to AIOHTTP.
URL: https://docs.aiohttp.org/en/stable/.
[17] Sanic Community. Sanic Framework.
URL: https://sanicframework.org/.
[18] Sebastián Ramírez. FastAPI.
URL: https://fastapi.tiangolo.com/.
[19] Encode OSS. Starlette.
URL: https://www.starlette.io/.
[20] Philip Jones. Quart Documentation.
URL: https://pgjones.gitlab.io/quart/.
[21] Canopy. asyncpgsa - A wrapper around asyncpg for use with sqlalchemy.
URL: https://github.com/CanopyTax/asyncpgsa.
[22] Fantix King. 表构造定义 - GINO 引擎.
URL: https://pythongino.org/docs/zh/master/how-to/schema.html#gino-engine.
[23] Fantix King. 表构造定义 - GINO core.
URL: https://python-gino.org/docs/zh/master/how-to/schema.html#gino-core.
[24] Fantix King. 表构造定义 - GINO ORM.
URL: https://python-gino.org/docs/zh/master/how-to/schema.html#gino-orm.
[25] MagicStack Inc. asyncpg - A fast PostgreSQL Database Client Library for Python/asyncio.
URL: https://github.com/MagicStack/asyncpg.
[26] MagicStack Inc. uvloop - Ultra fast asyncio event loop.
URL: https://github.com/MagicStack/uvloop.
[27] Tim Peters. PEP ‒ The Zen of Python.
URL: https://www.python.org/dev/peps/pep-0020/.
[28] Wikipedia. Plain old Java object.
URL: https://en.wikipedia.org/wiki/Plain_old_Java_object.
[29] Fantix King. 加载器与关系.
URL: https://python-gino.org/docs/zh/master/how-to/loaders.html.
[30] Andrey Bondar. Tortoise ORM.
URL: https://tortoise.github.io/.
[31] Encode OSS. ORM - An async ORM.
URL: https://github.com/encode/orm.
[32] Yury Selivanov. PEP ‒ Coroutines with async and await syntax.
URL: https://www.python.org/dev/peps/pep-0492/. (Apr , ).
想要得到更多数据科学领域干系动态,诚邀关注清华-青岛数据科学研究院官方微信"大众年夜众平台“ 数据派THU ”。