Skip to content

Commit 5c192a3

Browse files
committed
Fixes #308, refs #365, update docs
1 parent b4ffe01 commit 5c192a3

File tree

2 files changed

+87
-16
lines changed

2 files changed

+87
-16
lines changed

docs/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ Contents
5858
engine
5959
transaction
6060
crud
61-
relationship
61+
loaders
6262
adv_topics
6363
faq
6464
api

docs/relationship.rst renamed to docs/loaders.rst

Lines changed: 86 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
=============
2-
Relationships
3-
=============
1+
========================
2+
Loaders and Relationship
3+
========================
44

5-
As for now (April 2018) GINO has no full support for relationships. For one
6-
thing, we are still trying to find a decent way implementing relationships, for
7-
another, we insist explicit code style in asynchronous programming and that
8-
conflicts with some usual ORM relationship patterns. Still, GINO doesn't stop
9-
you from using relationships in the database through foreign keys or whatever
10-
magic, and gradually provides more features to support doing so.
5+
Loaders are used to load database row results into objects.
6+
7+
GINO doesn't support automated relationship. We insist explicit code style in
8+
asynchronous programming and that conflicts with some usual ORM relationship
9+
patterns. Instead, GINO provides a rich loader system to assist you with manual
10+
relationships through foreign keys or whatever magic. That means, you are
11+
responsible for writing the queries, and GINO could assemble objects for you
12+
from the database result with loaders you defined.
1113

1214

1315
Model Loader
@@ -68,12 +70,6 @@ there're also other loaders that could turn the database rows into different
6870
results like based on your definition. GINO provides the Loader Expression
6971
feature for you to easily assemble complex loaders.
7072

71-
72-
.. tip::
73-
74-
This is less relevant to relationships, please skip to the next section if
75-
it's not helpful for you.
76-
7773
Here is an example using all loaders at once::
7874

7975
uid, user, sep, cols = await db.select([User]).gino.load(
@@ -389,3 +385,78 @@ Similarly, you can build many-to-many relationships in the same way::
389385

390386
Likewise, there is for now no way to modify the relationships automatically,
391387
you'll have to manually create, delete or modify ``ParentXChild`` instances.
388+
389+
390+
Advanced Usage of Loaders
391+
-------------------------
392+
393+
You could use combined loaders flexibly in complex queries - loading
394+
relationships is just one special use case. For `example
395+
<https://github.com/fantix/gino/issues/308>`_, you could load the count of
396+
visits at the same time of loading each user, by using a tuple loader with two
397+
items - model loader for the user, and column loader for the count::
398+
399+
import asyncio
400+
import random
401+
import string
402+
403+
import gino
404+
from gino.loader import ColumnLoader
405+
406+
db = gino.Gino()
407+
408+
409+
class User(db.Model):
410+
__tablename__ = 'users'
411+
412+
id = db.Column(db.Integer(), primary_key=True)
413+
name = db.Column(db.Unicode())
414+
415+
416+
class Visit(db.Model):
417+
__tablename__ = 'visits'
418+
419+
id = db.Column(db.Integer(), primary_key=True)
420+
time = db.Column(db.DateTime(), server_default='now()')
421+
user_id = db.Column(db.ForeignKey('users.id'))
422+
423+
424+
async def main():
425+
async with db.with_bind('postgresql://localhost/gino'):
426+
await db.gino.create_all()
427+
428+
for i in range(random.randint(5, 10)):
429+
u = await User.create(
430+
name=''.join(random.choices(string.ascii_letters, k=10)))
431+
for v in range(random.randint(10, 20)):
432+
await Visit.create(user_id=u.id)
433+
434+
visits = db.func.count(Visit.id)
435+
q = db.select([
436+
User,
437+
visits,
438+
]).select_from(
439+
User.outerjoin(Visit)
440+
).group_by(
441+
*User,
442+
).gino.load((User, ColumnLoader(visits)))
443+
async with db.transaction():
444+
async for user, visits in q.iterate():
445+
print(user.name, visits)
446+
447+
await db.gino.drop_all()
448+
449+
450+
asyncio.run(main())
451+
452+
Using alias to get ID-ascending pairs from the same table::
453+
454+
ua1 = User.alias()
455+
ua2 = User.alias()
456+
join_query = select([ua1, ua2]).where(ua1.id < ua2.id)
457+
loader = ua1.load('id'), ua2.load('id')
458+
result = await join_query.gino.load(loader).all()
459+
print(result) # e.g. [(1, 2), (1, 3), (2, 3)]
460+
461+
Potentially there could be a lot of different use cases of loaders. We'll add
462+
more inspiration here in the future.

0 commit comments

Comments
 (0)