Source: GINO Official Document
This article is about 4810 words , and it is recommended to read 14 minutes .
This article introduces GitHub Thousand Star Project GINO—can access the database in a convenient, fast, and simple and clear manner.
With the emergence of frameworks such as Tornado[1] and asyncio[2], the topic of asynchronous programming of Python is gradually heating up. In this brain-burning asynchronous world, is there a way to access the database both convenient, fast, and simple and clear? GitHub Thousand Star Project GINO Learn about it!
1. Who is GINO
GINO is a "lightweight" asynchronous ORM framework. Its full name is GINO Is Not ORM, borrowing from the recursive definition [3] technique of GNU is Not Unix. So, GINO must be complete! department! big! Write! If "Gino" becomes a name like this, you must ask "Who is this".
ORM, i.e. relational object mapping (Object-Relational Mapping[4]), is a kind of efficiency tool that developers like, and they "greatly" improve the happiness index of code writing. GINO is used to access databases and also provides object mapping tools. So why not say that GINO is not an ORM?
Because things will turn out to be extreme, ORMs bring convenience to life, but they are also a breeding ground for bug growth. Traditional ORMs often choose to sacrifice clarity in exchange for convenience. Coupled with Python's unique flexibility, they create an explosive chemical reaction. Once the code begins to take shape, the project will more or less encounter ORM backlash: the performance is inexplicably poor, the cause of problems cannot be found, and the fight is made for trivial matters. Any word current_user.name may trigger a lot of unexpected database calls. How do you ask me to debug this code?
The learning curve of traditional ORM is flat at the front and steep at the back, and can show its skills in rapid prototype development, but it tests the average level of developers when applied to large projects.
If all these problems are put into the asynchronous programming environment, it is the complexity of O(n2) - Oh no, it is O(2n). This is unacceptable for an excellent asynchronous ORM framework, so GINO is an ORM but not a traditional ORM, just like GNU is not a traditional Unix, similar in shape but not in spirit.
So at the beginning of my creation in 2017, I set two performance goals for GINO: 1) Convenient and fast, 2) Simple and clear. Today, three years later, I simply made a year-end summary on the eve of the release of the 1.0 stable version.
2. Let’s talk about “convenient and fast” first.
“convenient and fast” mainly talks about development efficiency.
The concept of paying attention to development efficiency may not be unfamiliar to students who write Python. In some scenarios, developers' time is indeed more valuable than machine time. Therefore, object mapping in traditional ORM cannot be lost.
from gino import Ginodb = Gino()class User(db.Model):__tablename__ = "users"id = db.Column(db.Integer, primary_key=True)name=db.Column(db.String)
This way of defining the table structure is even a little excited. Hey, why do you look so familiar?
is not wrong, this is the definition style of SQLAlchemy ORM[5]. GINO is not built from scratch, but is developed based on SQLAlchemy core[6] (the underlying core in SQLAlchemy). In addition to maintaining a familiar taste (to save learning and migration costs), this has more importantly brought about the entire SQLAlchemy ecological environment: out-of-the-box database change management tool Alembic[7], various SQLAlchemy enhancement plug-ins[8], PostGIS/geoalchemy[9] in professional fields, etc., GINO is all compatible. Is
very convenient and fast? More than that.
GINO solves a number of convenient functions such as commonly used CRUD shortcuts [10], context management (aiocontextvars[11][12]), database transaction encapsulation and nesting [13], connection pool management and lazy loading [14] in one-stop, without additional dependencies, ready-to-install.
daisy = await User.create(name="daisy")awaitdaisy.update(name="Daisy").apply()
GINO also provides customized plugins for the [15] major popular asynchronous web frameworks. They can call names such as Tornado[1], aiohttp[16], Sanic[17], FastAPI[18]/Starlette[19], Quart[20], etc. There are a variety of examples from simple demonstration to production environments. Mom no longer has to worry that I will not integrate the web framework.
In order to allow users in different application scenarios to experience the greatest kindness, GINO currently supports three different degrees of usage, successfully achieving a dimensionality reduction blow to the competitor asyncpgsa[21] during the same period:
- least invasive [22]: SQLAlchemy core fundamentalist, GINO is only used when executing asynchronously.
- Lifetime non-marriage type [23]: Born to hate "objects", only want to define "tables", and take SQL with empty hands.
- full firepower model [24]: Maximum convenience, atypical asynchronous ORM.
Finally, although it is Python (never a black ha), GINO has not lost its execution efficiency. Based on the strong support of MagicStack, asyncpg[25] that can read million lines in one second, and uvloop[26] (optional), GINO can run quickly and is widely used in high-concurrency fields such as real-time exchange rates, chatbots, online games, etc., and is deeply loved by the Russian and Ukrainian people.
3. Let’s talk about “simple and clear”
Explicit is better than implicit.
Simple is better than complex.
-- The Zen of Python, PEP 20[27]
Python Zen perfectly expresses GINO’s position—clearity (explicitness) is particularly important for asynchronous engineering projects that are on a scale, so many of GINO’s designs are affected by clarity.
For example, GINO's Model is a completely stateless ordinary Python object (POPO[28]) - For example, the previous User class, its instance
daisy is a regular object in memory. You can use daisy.name to access the attribute, or use daisy.name = "DAISY" to modify the attribute, or use u = User() to create a new instance. These operations will not access the database, which is absolutely green, environmentally friendly and has no toxic side effects.
When you need to operate the database, you will definitely have a sense of it. For example, when executing INSERT, you need to use u = await User.create(), while UPDATE is await u.update(name="Daisy").apply().
where, u.update(name="Daisy") is similar to u.name = "Daisy", both of which only modify the properties of the object in memory. The difference is that u.update() will also return an intermediate result containing this change. Execute await xxx.apply() on it and apply these changes to the database.
The await here is the key to clarity, which means we have to jump out and execute database operations. In other words, without await there is no database operation.
On the other hand, GINO also has a set of exquisite explicit mechanisms for how to assemble database query results into memory objects and their properties - customizable loaders loaders[29]. For simple and intuitive one-to-one loading, GINO is naturally used to serve home. For example, using u = await User.get(1) you can directly obtain a user object with ID 1. However, for more complex queries, GINO will not make unreasonable guesses about the owner's intentions, but will leave it to the user to clearly define it.The usage of the loader is also very simple. For example, a user may have written many books:
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")
Then load this many-to-one relationship to get all the books and their authors at the same time:
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)
is a very simple external connection query Book.outerjoin(User), combined with an intuitive loader Book.load(author=User), implements:
- executes SELECT * FROM books LEFT JOIN users ON ...;
- loads the fields belonging to books in each row of the database return result, and loads the fields belonging to books into a Book Instance;
- then load the remaining fields belonging to users in the row into a User instance;
- finally sets the User instance to the author attribute of the Book instance.
is both simple and clear! You can even hand-written any SQL, and then customize the loader to automatically load into the desired object relationship, accurately control the loading behavior, and hit wherever you point. GINO has many similar features, so I won't list them all here.
4. Advantages and Deficiencies
As GINO continues to evolve and mature in recent years, excellent asynchronous ORM frameworks such as Tortoise ORM[30] and ORM[31] (yes, this project is called ORM... I am really ORZ. The producer is Encode, and Starlette is their work) have also appeared in the open source community of Python. Their focus is slightly different from GINO, but I won’t comment much on them all in my peers. The biggest advantage of
GINO is that it fully balances the dialectical contradiction between development efficiency and clarity. When developing applications with GINO, you don’t have to worry about being frightened by unexpected behaviors, and you don’t need to pay too much engineering cost for this clarity. You can still program quickly and happily after getting started. At the same time, a large number of successful cases have proved that GINO has initially met the various conditions for releasing the 1.0 stable version and can be used in production environments with caution.
The following are recent application cases about GINO:
- A service developed by the author at work: https://github.com/uc-cdis/metadata-service
- is also a tool written by the author himself: https://github.com/fantix/aintq
- An exchange rate API service: https://exchangeratessapi.io/
- Various Telegram and Discord Bots.
- ArchLinux User package: https://aur.archlinux.org/packages/python-gino/
- https://github.com/bryanforbes/gino-stubs/
- Russian tutorial: https://www.youtube.com/watch?v=WW4rOnfhiQY
- High-performance template project: https://github.com/leosussan/fastapi-gino-arq-uvicorn
- There are several commercial ones, but they will not be posted without permission.
In addition, GINO also provides Chinese documents [32] thoughtfully, from the tutorial to the principle description (although the document is still being written!):
GINO has some shortcomings, such as not taking into account the type prompts of Python 3, so it cannot fully realize the potential of the IDE (the gino-stubs above is that some people can't stand it and wrote a type annotation themselves). MySQL is not currently supported, but GINO has decoupled the integration of different SQL dialects and drivers since a long time ago, so these functions will be followed in versions 1.1 and 1.2 one after another.
5. Building socialism
GINO is an open source project , so everyone is welcome to build it together!
Currently, those who need help in urgent need are: the maintenance of various web framework plug-ins of
- require multiple people to claim;
- more examples and documents, as well as translations in Chinese and Russian;
- MySQL support.
and the following help you have been needed:
- use GINO to find bugs, make suggestions;
- fix bugs, do functions, and provide PR;
- maintains the community, answer questions, and participate in discussions;
- last and most important: go to GitHub to add a star to GINO!
6. About the author
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 Born in 6 years, he started to come into contact with programming at the age of 6. Twenty-five and six years of programming history and thirteen or fourteen years of work experience have taught me many of the secrets of software development. When I was a child, I wrote GBasic, QBasic and Visual Basic; I started writing Java in college and came into contact with open source projects such as FreeBSD and Ubuntu and it was out of control. In the first five years of work, I turned to Python, learned about asynchronous programming through projects such as Twisted and Eventlet, and contributed to Gevent's Python 3 migration during this period. I also left a figure in the trend of entrepreneurship, personally experienced and witnessed the ups and downs of software technology with the industries of mobile games, new media, mining circles, Internet finance, e-commerce, social networking, entertainment, automobiles, etc.; I am currently continuing to do open source projects related to biological big data at Zhida University.
Source: GINO Official Document
This article is about 4810 words , and it is recommended to read 14 minutes .
This article introduces GitHub Thousand Star Project GINO—can access the database in a convenient, fast, and simple and clear manner.
With the emergence of frameworks such as Tornado[1] and asyncio[2], the topic of asynchronous programming of Python is gradually heating up. In this brain-burning asynchronous world, is there a way to access the database both convenient, fast, and simple and clear? GitHub Thousand Star Project GINO Learn about it!
1. Who is GINO
GINO is a "lightweight" asynchronous ORM framework. Its full name is GINO Is Not ORM, borrowing from the recursive definition [3] technique of GNU is Not Unix. So, GINO must be complete! department! big! Write! If "Gino" becomes a name like this, you must ask "Who is this".
ORM, i.e. relational object mapping (Object-Relational Mapping[4]), is a kind of efficiency tool that developers like, and they "greatly" improve the happiness index of code writing. GINO is used to access databases and also provides object mapping tools. So why not say that GINO is not an ORM?
Because things will turn out to be extreme, ORMs bring convenience to life, but they are also a breeding ground for bug growth. Traditional ORMs often choose to sacrifice clarity in exchange for convenience. Coupled with Python's unique flexibility, they create an explosive chemical reaction. Once the code begins to take shape, the project will more or less encounter ORM backlash: the performance is inexplicably poor, the cause of problems cannot be found, and the fight is made for trivial matters. Any word current_user.name may trigger a lot of unexpected database calls. How do you ask me to debug this code?
The learning curve of traditional ORM is flat at the front and steep at the back, and can show its skills in rapid prototype development, but it tests the average level of developers when applied to large projects.
If all these problems are put into the asynchronous programming environment, it is the complexity of O(n2) - Oh no, it is O(2n). This is unacceptable for an excellent asynchronous ORM framework, so GINO is an ORM but not a traditional ORM, just like GNU is not a traditional Unix, similar in shape but not in spirit.
So at the beginning of my creation in 2017, I set two performance goals for GINO: 1) Convenient and fast, 2) Simple and clear. Today, three years later, I simply made a year-end summary on the eve of the release of the 1.0 stable version.
2. Let’s talk about “convenient and fast” first.
“convenient and fast” mainly talks about development efficiency.
The concept of paying attention to development efficiency may not be unfamiliar to students who write Python. In some scenarios, developers' time is indeed more valuable than machine time. Therefore, object mapping in traditional ORM cannot be lost.
from gino import Ginodb = Gino()class User(db.Model):__tablename__ = "users"id = db.Column(db.Integer, primary_key=True)name=db.Column(db.String)
This way of defining the table structure is even a little excited. Hey, why do you look so familiar?
is not wrong, this is the definition style of SQLAlchemy ORM[5]. GINO is not built from scratch, but is developed based on SQLAlchemy core[6] (the underlying core in SQLAlchemy). In addition to maintaining a familiar taste (to save learning and migration costs), this has more importantly brought about the entire SQLAlchemy ecological environment: out-of-the-box database change management tool Alembic[7], various SQLAlchemy enhancement plug-ins[8], PostGIS/geoalchemy[9] in professional fields, etc., GINO is all compatible. Is
very convenient and fast? More than that.
GINO solves a number of convenient functions such as commonly used CRUD shortcuts [10], context management (aiocontextvars[11][12]), database transaction encapsulation and nesting [13], connection pool management and lazy loading [14] in one-stop, without additional dependencies, ready-to-install.
daisy = await User.create(name="daisy")awaitdaisy.update(name="Daisy").apply()
GINO also provides customized plugins for the [15] major popular asynchronous web frameworks. They can call names such as Tornado[1], aiohttp[16], Sanic[17], FastAPI[18]/Starlette[19], Quart[20], etc. There are a variety of examples from simple demonstration to production environments. Mom no longer has to worry that I will not integrate the web framework.
In order to allow users in different application scenarios to experience the greatest kindness, GINO currently supports three different degrees of usage, successfully achieving a dimensionality reduction blow to the competitor asyncpgsa[21] during the same period:
- least invasive [22]: SQLAlchemy core fundamentalist, GINO is only used when executing asynchronously.
- Lifetime non-marriage type [23]: Born to hate "objects", only want to define "tables", and take SQL with empty hands.
- full firepower model [24]: Maximum convenience, atypical asynchronous ORM.
Finally, although it is Python (never a black ha), GINO has not lost its execution efficiency. Based on the strong support of MagicStack, asyncpg[25] that can read million lines in one second, and uvloop[26] (optional), GINO can run quickly and is widely used in high-concurrency fields such as real-time exchange rates, chatbots, online games, etc., and is deeply loved by the Russian and Ukrainian people.
3. Let’s talk about “simple and clear”
Explicit is better than implicit.
Simple is better than complex.
-- The Zen of Python, PEP 20[27]
Python Zen perfectly expresses GINO’s position—clearity (explicitness) is particularly important for asynchronous engineering projects that are on a scale, so many of GINO’s designs are affected by clarity.
For example, GINO's Model is a completely stateless ordinary Python object (POPO[28]) - For example, the previous User class, its instance
daisy is a regular object in memory. You can use daisy.name to access the attribute, or use daisy.name = "DAISY" to modify the attribute, or use u = User() to create a new instance. These operations will not access the database, which is absolutely green, environmentally friendly and has no toxic side effects.
When you need to operate the database, you will definitely have a sense of it. For example, when executing INSERT, you need to use u = await User.create(), while UPDATE is await u.update(name="Daisy").apply().
where, u.update(name="Daisy") is similar to u.name = "Daisy", both of which only modify the properties of the object in memory. The difference is that u.update() will also return an intermediate result containing this change. Execute await xxx.apply() on it and apply these changes to the database.
The await here is the key to clarity, which means we have to jump out and execute database operations. In other words, without await there is no database operation.
On the other hand, GINO also has a set of exquisite explicit mechanisms for how to assemble database query results into memory objects and their properties - customizable loaders loaders[29]. For simple and intuitive one-to-one loading, GINO is naturally used to serve home. For example, using u = await User.get(1) you can directly obtain a user object with ID 1. However, for more complex queries, GINO will not make unreasonable guesses about the owner's intentions, but will leave it to the user to clearly define it.The usage of the loader is also very simple. For example, a user may have written many books:
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")
Then load this many-to-one relationship to get all the books and their authors at the same time:
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)
is a very simple external connection query Book.outerjoin(User), combined with an intuitive loader Book.load(author=User), implements:
- executes SELECT * FROM books LEFT JOIN users ON ...;
- loads the fields belonging to books in each row of the database return result, and loads the fields belonging to books into a Book Instance;
- then load the remaining fields belonging to users in the row into a User instance;
- finally sets the User instance to the author attribute of the Book instance.
is both simple and clear! You can even hand-written any SQL, and then customize the loader to automatically load into the desired object relationship, accurately control the loading behavior, and hit wherever you point. GINO has many similar features, so I won't list them all here.
4. Advantages and Deficiencies
As GINO continues to evolve and mature in recent years, excellent asynchronous ORM frameworks such as Tortoise ORM[30] and ORM[31] (yes, this project is called ORM... I am really ORZ. The producer is Encode, and Starlette is their work) have also appeared in the open source community of Python. Their focus is slightly different from GINO, but I won’t comment much on them all in my peers. The biggest advantage of
GINO is that it fully balances the dialectical contradiction between development efficiency and clarity. When developing applications with GINO, you don’t have to worry about being frightened by unexpected behaviors, and you don’t need to pay too much engineering cost for this clarity. You can still program quickly and happily after getting started. At the same time, a large number of successful cases have proved that GINO has initially met the various conditions for releasing the 1.0 stable version and can be used in production environments with caution.
The following are recent application cases about GINO:
- A service developed by the author at work: https://github.com/uc-cdis/metadata-service
- is also a tool written by the author himself: https://github.com/fantix/aintq
- An exchange rate API service: https://exchangeratessapi.io/
- Various Telegram and Discord Bots.
- ArchLinux User package: https://aur.archlinux.org/packages/python-gino/
- https://github.com/bryanforbes/gino-stubs/
- Russian tutorial: https://www.youtube.com/watch?v=WW4rOnfhiQY
- High-performance template project: https://github.com/leosussan/fastapi-gino-arq-uvicorn
- There are several commercial ones, but they will not be posted without permission.
In addition, GINO also provides Chinese documents [32] thoughtfully, from the tutorial to the principle description (although the document is still being written!):
GINO has some shortcomings, such as not taking into account the type prompts of Python 3, so it cannot fully realize the potential of the IDE (the gino-stubs above is that some people can't stand it and wrote a type annotation themselves). MySQL is not currently supported, but GINO has decoupled the integration of different SQL dialects and drivers since a long time ago, so these functions will be followed in versions 1.1 and 1.2 one after another.
5. Building socialism
GINO is an open source project , so everyone is welcome to build it together!
Currently, those who need help in urgent need are: the maintenance of various web framework plug-ins of
- require multiple people to claim;
- more examples and documents, as well as translations in Chinese and Russian;
- MySQL support.
and the following help you have been needed:
- use GINO to find bugs, make suggestions;
- fix bugs, do functions, and provide PR;
- maintains the community, answer questions, and participate in discussions;
- last and most important: go to GitHub to add a star to GINO!
6. About the author
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 Born in 6 years, he started to come into contact with programming at the age of 6. Twenty-five and six years of programming history and thirteen or fourteen years of work experience have taught me many of the secrets of software development. When I was a child, I wrote GBasic, QBasic and Visual Basic; I started writing Java in college and came into contact with open source projects such as FreeBSD and Ubuntu and it was out of control. In the first five years of work, I turned to Python, learned about asynchronous programming through projects such as Twisted and Eventlet, and contributed to Gevent's Python 3 migration during this period. I also left a figure in the trend of entrepreneurship, personally experienced and witnessed the ups and downs of software technology with the industries of mobile games, new media, mining circles, Internet finance, e-commerce, social networking, entertainment, automobiles, etc.; I am currently continuing to do open source projects related to biological big data at Zhida University.In addition to developing and maintaining GINO projects in my spare time, I will occasionally repair bugs for uvloop, asyncpg and CPython:P
7. Reference
[1] Facebook. Tornado.
URL: https://zh.wikipedia.org/wiki/Tornado.
[2] Python Software Foundation. asyncio — Asynchronous I/O.
URL: https://docs.python.org/zh-cn/3/library/asyncio.html.
[3] Wikipedia. GNU.
URL: https://zh.wikipedia.org/wiki/GNU.
[4] Wikipedia. Object relational mapping.
URL: https://zh.wikipedia.org/wiki/Object relational mapping
[5] Wikipedia. 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 Basic Tutorial - Add, delete, modify and check.
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. Database transaction.
URL: https://python-gino.org/docs/zh/master/how-to/transaction.html.
[14] Fantix King. Engine and Connection.
URL: https://python-gino.org/docs/zh/master/explanation/engine.html.
[15] GINO Community. 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. Table structure definition - GINO engine.
URL: https://pythongino.org/docs/zh/master/how-to/schema.html#gino-engine.
[23] Fantix King. Table structure definition - GINO core.
URL: https://python-gino.org/docs/zh/master/how-to/schema.html#gino-core.
[24] Fantix King. Table structure definition - 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. Loader and Relationship.
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, ).
If you want to get more relevant news in the field of data science, you sincerely invite you to follow the official WeChat public platform of Tsinghua-Qingdao Data Science Research Institute " Data Send THU".