Skip to content
This repository was archived by the owner on Aug 19, 2025. It is now read-only.

Commit ea9153a

Browse files
authored
documentation (#103)
1 parent 569585c commit ea9153a

File tree

10 files changed

+454
-141
lines changed

10 files changed

+454
-141
lines changed

README.md

Lines changed: 3 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -62,156 +62,21 @@ class Note(orm.Model):
6262
__tablename__ = "notes"
6363
__database__ = database
6464
__metadata__ = metadata
65-
6665
id = orm.Integer(primary_key=True)
6766
text = orm.String(max_length=100)
6867
completed = orm.Boolean(default=False)
6968

70-
# Create the database
69+
# Create the database and tables
7170
engine = sqlalchemy.create_engine(str(database.url))
7271
metadata.create_all(engine)
7372

74-
# .create()
7573
await Note.objects.create(text="Buy the groceries.", completed=False)
76-
await Note.objects.create(text="Call Mum.", completed=True)
77-
await Note.objects.create(text="Send invoices.", completed=True)
78-
79-
# .all()
80-
notes = await Note.objects.all()
81-
82-
# .filter()
83-
notes = await Note.objects.filter(completed=True).all()
84-
85-
# .exclude()
86-
notes = await Note.objects.exclude(completed=False).all()
8774

88-
# exact, iexact, contains, icontains, lt, lte, gt, gte, in
89-
notes = await Note.objects.filter(text__icontains="mum").all()
90-
91-
# .order_by()
92-
# order by ascending name and descending id
93-
notes = await Note.objects.order_by("name", "-id").all()
94-
95-
# .get()
9675
note = await Note.objects.get(id=1)
97-
98-
# .first()
99-
note = await Note.objects.filter(completed=True).first()
100-
101-
# .update()
102-
await note.update(completed=True)
103-
104-
# .delete()
105-
await note.delete()
106-
107-
# 'pk' always refers to the primary key
108-
note = await Note.objects.get(pk=2)
109-
note.pk # 2
110-
76+
print(note)
77+
# Note(id=1, text="Buy the groceries.", completed=False)
11178
```
11279

113-
ORM supports loading and filtering across foreign keys...
114-
115-
```python
116-
import databases
117-
import orm
118-
import sqlalchemy
119-
120-
database = databases.Database("sqlite:///db.sqlite")
121-
metadata = sqlalchemy.MetaData()
122-
123-
124-
class Album(orm.Model):
125-
__tablename__ = "album"
126-
__metadata__ = metadata
127-
__database__ = database
128-
129-
id = orm.Integer(primary_key=True)
130-
name = orm.String(max_length=100)
131-
132-
133-
class Track(orm.Model):
134-
__tablename__ = "track"
135-
__metadata__ = metadata
136-
__database__ = database
137-
138-
id = orm.Integer(primary_key=True)
139-
album = orm.ForeignKey(Album)
140-
title = orm.String(max_length=100)
141-
position = orm.Integer()
142-
143-
144-
# Create some records to work with.
145-
malibu = await Album.objects.create(name="Malibu")
146-
await Track.objects.create(album=malibu, title="The Bird", position=1)
147-
await Track.objects.create(album=malibu, title="Heart don't stand a chance", position=2)
148-
await Track.objects.create(album=malibu, title="The Waters", position=3)
149-
150-
fantasies = await Album.objects.create(name="Fantasies")
151-
await Track.objects.create(album=fantasies, title="Help I'm Alive", position=1)
152-
await Track.objects.create(album=fantasies, title="Sick Muse", position=2)
153-
154-
155-
# Fetch an instance, without loading a foreign key relationship on it.
156-
track = await Track.objects.get(title="The Bird")
157-
158-
# We have an album instance, but it only has the primary key populated
159-
print(track.album) # Album(id=1) [sparse]
160-
print(track.album.pk) # 1
161-
print(track.album.name) # Raises AttributeError
162-
163-
# Load the relationship from the database
164-
await track.album.load()
165-
assert track.album.name == "Malibu"
166-
167-
# This time, fetch an instance, loading the foreign key relationship.
168-
track = await Track.objects.select_related("album").get(title="The Bird")
169-
assert track.album.name == "Malibu"
170-
171-
# Fetch instances, with a filter across an FK relationship.
172-
tracks = Track.objects.filter(album__name="Fantasies")
173-
assert len(tracks) == 2
174-
175-
# Fetch instances, with a filter and operator across an FK relationship.
176-
tracks = Track.objects.filter(album__name__iexact="fantasies")
177-
assert len(tracks) == 2
178-
179-
# Limit a query
180-
tracks = await Track.objects.limit(1).all()
181-
assert len(tracks) == 1
182-
```
183-
184-
## Data types
185-
186-
The following keyword arguments are supported on all field types.
187-
188-
* `primary_key`
189-
* `allow_null`
190-
* `default`
191-
* `index`
192-
* `unique`
193-
194-
All fields are required unless one of the following is set:
195-
196-
* `allow_null` - Creates a nullable column. Sets the default to `None`.
197-
* `allow_blank` - Allow empty strings to validate. Sets the default to `""`.
198-
* `default` - Set a default value for the field.
199-
200-
The following column types are supported.
201-
See TypeSystem for [type-specific validation keyword arguments][typesystem-fields].
202-
203-
* `orm.BigInteger()`
204-
* `orm.Boolean()`
205-
* `orm.Date()`
206-
* `orm.DateTime()`
207-
* `orm.Enum()`
208-
* `orm.Float()`
209-
* `orm.Integer()`
210-
* `orm.String(max_length)`
211-
* `orm.Text()`
212-
* `orm.Time()`
213-
* `orm.JSON()`
214-
21580
[sqlalchemy-core]: https://docs.sqlalchemy.org/en/latest/core/
21681
[alembic]: https://alembic.sqlalchemy.org/en/latest/
21782
[psycopg2]: https://www.psycopg.org/

docs/declaring_models.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
## Declaring models
2+
3+
You can define models by inheriting from `orm.Model` and
4+
defining model fields as attributes in the class.
5+
For each defined model you need to set two special variables:
6+
7+
* `__database__` for database connection.
8+
* `__metadata__` for `SQLAlchemy` functions and migrations.
9+
10+
You can also specify the table name in database by setting `__tablename__` attribute.
11+
12+
```python
13+
import databases
14+
import orm
15+
import sqlalchemy
16+
17+
database = databases.Database("sqlite:///db.sqlite")
18+
metadata = sqlalchemy.MetaData()
19+
20+
21+
class Note(orm.Model):
22+
__tablename__ = "notes"
23+
__database__ = database
24+
__metadata__ = metadata
25+
26+
id = orm.Integer(primary_key=True)
27+
text = orm.String(max_length=100)
28+
completed = orm.Boolean(default=False)
29+
```
30+
31+
ORM can create or drop database and tables from models using SQLAlchemy.
32+
For using these functions or `Alembic` migrations, you still have to
33+
install a synchronous DB driver: [psycopg2][psycopg2] for PostgreSQL and [pymysql][pymysql] for MySQL.
34+
35+
Afer installing a synchronous DB driver, you can create tables for the models using:
36+
37+
```python
38+
engine = sqlalchemy.create_engine(str(database.url))
39+
metadata.create_all(engine)
40+
```
41+
42+
## Data types
43+
44+
The following keyword arguments are supported on all field types.
45+
46+
* `primary_key` - A boolean. Determine if column is primary key.
47+
* `allow_null` - A boolean. Determine if column is nullable.
48+
* `default` - A value or a callable (function).
49+
* `index` - A boolean. Determine if database indexes should be created.
50+
* `unique` - A boolean. Determine if unique constraint should be created.
51+
52+
All fields are required unless one of the following is set:
53+
54+
* `allow_null` - A boolean. Determine if column is nullable. Sets the default to `None`.
55+
* `allow_blank` - A boolean. Determine if empty strings are allowed. Sets the default to `""`.
56+
* `default` - A value or a callable (function).
57+
58+
The following column types are supported.
59+
See `TypeSystem` for [type-specific validation keyword arguments][typesystem-fields].
60+
61+
* `orm.BigInteger()`
62+
* `orm.Boolean()`
63+
* `orm.Date()`
64+
* `orm.DateTime()`
65+
* `orm.Enum()`
66+
* `orm.Float()`
67+
* `orm.Integer()`
68+
* `orm.String(max_length)`
69+
* `orm.Text()`
70+
* `orm.Time()`
71+
* `orm.JSON()`
72+
73+
[psycopg2]: https://www.psycopg.org/
74+
[pymysql]: https://github.com/PyMySQL/PyMySQL
75+
[typesystem-fields]: https://www.encode.io/typesystem/fields/

docs/index.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# ORM
2+
3+
<p>
4+
<a href="https://github.com/encode/orm/actions">
5+
<img src="https://github.com/encode/orm/workflows/Test%20Suite/badge.svg" alt="Build Status">
6+
</a>
7+
<a href="https://codecov.io/gh/encode/orm">
8+
<img src="https://codecov.io/gh/encode/orm/branch/master/graph/badge.svg" alt="Coverage">
9+
</a>
10+
<a href="https://pypi.org/project/orm/">
11+
<img src="https://badge.fury.io/py/orm.svg" alt="Package version">
12+
</a>
13+
</p>
14+
15+
The `orm` package is an async ORM for Python, with support for Postgres,
16+
MySQL, and SQLite. ORM is built with:
17+
18+
* [SQLAlchemy core][sqlalchemy-core] for query building.
19+
* [`databases`][databases] for cross-database async support.
20+
* [`typesystem`][typesystem] for data validation.
21+
22+
Because ORM is built on SQLAlchemy core, you can use Alembic to provide
23+
database migrations.
24+
25+
**ORM is still under development: We recommend pinning any dependencies with `orm~=0.1`**
26+
27+
---
28+
29+
## Installation
30+
31+
```shell
32+
$ pip install orm
33+
```
34+
35+
You can install the required database drivers with:
36+
37+
```shell
38+
$ pip install orm[postgresql]
39+
$ pip install orm[mysql]
40+
$ pip install orm[sqlite]
41+
```
42+
43+
Driver support is provided using one of [asyncpg][asyncpg], [aiomysql][aiomysql], or [aiosqlite][aiosqlite].
44+
Note that if you are using any synchronous SQLAlchemy functions such as `engine.create_all()` or [alembic][alembic] migrations then you still have to install a synchronous DB driver: [psycopg2][psycopg2] for PostgreSQL and [pymysql][pymysql] for MySQL.
45+
46+
---
47+
48+
## Quickstart
49+
50+
**Note**: Use `ipython` to try this from the console, since it supports `await`.
51+
52+
```python
53+
import databases
54+
import orm
55+
import sqlalchemy
56+
57+
database = databases.Database("sqlite:///db.sqlite")
58+
metadata = sqlalchemy.MetaData()
59+
60+
61+
class Note(orm.Model):
62+
__tablename__ = "notes"
63+
__database__ = database
64+
__metadata__ = metadata
65+
id = orm.Integer(primary_key=True)
66+
text = orm.String(max_length=100)
67+
completed = orm.Boolean(default=False)
68+
69+
# Create the database and tables
70+
engine = sqlalchemy.create_engine(str(database.url))
71+
metadata.create_all(engine)
72+
73+
await Note.objects.create(text="Buy the groceries.", completed=False)
74+
75+
note = await Note.objects.get(id=1)
76+
print(note)
77+
# Note(id=1, text="Buy the groceries.", completed=False)
78+
```
79+
80+
[sqlalchemy-core]: https://docs.sqlalchemy.org/en/latest/core/
81+
[alembic]: https://alembic.sqlalchemy.org/en/latest/
82+
[psycopg2]: https://www.psycopg.org/
83+
[pymysql]: https://github.com/PyMySQL/PyMySQL
84+
[asyncpg]: https://github.com/MagicStack/asyncpg
85+
[aiomysql]: https://github.com/aio-libs/aiomysql
86+
[aiosqlite]: https://github.com/jreese/aiosqlite
87+
88+
[databases]: https://github.com/encode/databases
89+
[typesystem]: https://github.com/encode/typesystem
90+
[typesystem-fields]: https://www.encode.io/typesystem/fields/

0 commit comments

Comments
 (0)