@@ -18,10 +18,11 @@ It allows you to make queries using the powerful [SQLAlchemy Core][sqlalchemy-co
18
18
expression language, and provides support for PostgreSQL, MySQL, and SQLite.
19
19
20
20
Databases is suitable for integrating against any async Web framework, such as [ Starlette] [ starlette ] ,
21
- [ Sanic] [ sanic ] , [ Responder] [ responder ] , [ Quart] [ quart ] , [ aiohttp] [ aiohttp ] , [ Tornado] [ tornado ] , [ FastAPI] [ fastapi ] ,
22
- or [ Bocadillo] [ bocadillo ] .
21
+ [ Sanic] [ sanic ] , [ Responder] [ responder ] , [ Quart] [ quart ] , [ aiohttp] [ aiohttp ] , [ Tornado] [ tornado ] , [ FastAPI] [ fastapi ] , or [ Bocadillo] [ bocadillo ] .
23
22
24
- ** Community** : https://discuss.encode.io/c/databases
23
+ ** Documentation** : [ https://www.encode.io/databases/ ] ( https://www.encode.io/databases/ )
24
+
25
+ ** Community** : [ https://discuss.encode.io/c/databases ] ( https://discuss.encode.io/c/databases )
25
26
26
27
** Requirements** : Python 3.6+
27
28
@@ -43,278 +44,51 @@ $ pip install databases[sqlite]
43
44
44
45
Driver support is providing using one of [ asyncpg] [ asyncpg ] , [ aiomysql] [ aiomysql ] , or [ aiosqlite] [ aiosqlite ] .
45
46
46
- ## Getting started
47
-
48
- ** Note** : Use ` ipython ` to try these example from the console, since it supports ` await ` .
49
-
50
- Declare your tables using SQLAlchemy:
51
-
52
- ``` python
53
- import sqlalchemy
47
+ ---
54
48
49
+ ## Quickstart
55
50
56
- metadata = sqlalchemy.MetaData()
51
+ For this example we'll create a very simple SQLite database to run some
52
+ queries against.
57
53
58
- notes = sqlalchemy.Table(
59
- " notes" ,
60
- metadata,
61
- sqlalchemy.Column(" id" , sqlalchemy.Integer, primary_key = True ),
62
- sqlalchemy.Column(" text" , sqlalchemy.String(length = 100 )),
63
- sqlalchemy.Column(" completed" , sqlalchemy.Boolean),
64
- )
54
+ ``` shell
55
+ $ pip install databases[sqlite]
56
+ $ pip install ipython
65
57
```
66
58
59
+ We can now run a simple example from the console.
67
60
68
- You can use any of the sqlalchemy column types such as ` sqlalchemy.JSON ` , or
69
- custom column types.
70
-
71
- ## Queries
72
-
73
- You can now use any [ SQLAlchemy core] [ sqlalchemy-core ] queries ([ official tutorial] [ sqlalchemy-core-tutorial ] ).
61
+ Note that we want to use ` ipython ` here, because it supports using ` await `
62
+ expressions directly from the console.
74
63
75
64
``` python
65
+ # Create a database instance, and connect to it.
76
66
from databases import Database
77
-
78
- database = Database(' postgresql://localhost/example' )
79
-
80
-
81
- # Establish the connection pool
67
+ database = Database(' sqlite:///example.db' )
82
68
await database.connect()
83
69
84
- # Execute
85
- query = notes.insert()
86
- values = {" text" : " example1" , " completed" : True }
87
- await database.execute(query = query, values = values)
70
+ # Create a table.
71
+ query = """ CREATE TABLE HighScores (id INTEGER PRIMARY KEY, name VARCHAR(100), score INTEGER)"""
72
+ await database.execute(query = query)
88
73
89
- # Execute many
90
- query = notes.insert()
74
+ # Insert some data.
75
+ query = " INSERT INTO HighScores(name, score) VALUES (:name, :score) "
91
76
values = [
92
- {" text" : " example2" , " completed" : False },
93
- {" text" : " example3" , " completed" : True },
77
+ {" name" : " Daisy" , " score" : 92 },
78
+ {" name" : " Neil" , " score" : 87 },
79
+ {" name" : " Carol" , " score" : 43 },
94
80
]
95
81
await database.execute_many(query = query, values = values)
96
82
97
- # Fetch multiple rows
98
- query = notes.select()
83
+ # Run a database query.
84
+ query = " SELECT * FROM HighScores "
99
85
rows = await database.fetch_all(query = query)
100
-
101
- # Fetch single row
102
- query = notes.select()
103
- row = await database.fetch_one(query = query)
104
-
105
- # Fetch single value, defaults to `column=0`.
106
- query = notes.select()
107
- value = await database.fetch_val(query = query)
108
-
109
- # Fetch multiple rows without loading them all into memory at once
110
- query = notes.select()
111
- async for row in database.iterate(query = query):
112
- ...
113
-
114
- # Close all connection in the connection pool
115
- await database.disconnect()
116
- ```
117
-
118
- Connections are managed as task-local state, with driver implementations
119
- transparently using connection pooling behind the scenes.
120
-
121
- ## Raw queries
122
-
123
- In addition to SQLAlchemy core queries, you can also perform raw SQL queries:
124
-
125
- ``` python
126
- # Execute
127
- query = " INSERT INTO notes(text, completed) VALUES (:text, :completed)"
128
- values = {" text" : " example1" , " completed" : True }
129
- await database.execute(query = query, values = values)
130
-
131
- # Execute many
132
- query = " INSERT INTO notes(text, completed) VALUES (:text, :completed)"
133
- values = [
134
- {" text" : " example2" , " completed" : False },
135
- {" text" : " example3" , " completed" : True },
136
- ]
137
- await database.execute_many(query = query, values = values)
138
-
139
- # Fetch multiple rows
140
- query = " SELECT * FROM notes WHERE completed = :completed"
141
- rows = await database.fetch_all(query = query, values = {" completed" : True })
142
-
143
- # Fetch single row
144
- query = " SELECT * FROM notes WHERE id = :id"
145
- result = await database.fetch_one(query = query, values = {" id" : 1 })
146
- ```
147
-
148
- Note that query arguments should follow the ` :query_arg ` style.
149
-
150
- ## Transactions
151
-
152
- Transactions are managed by async context blocks:
153
-
154
- ``` python
155
- async with database.transaction():
156
- ...
157
- ```
158
-
159
- For a lower-level transaction API:
160
-
161
- ``` python
162
- transaction = await database.transaction()
163
- try :
164
- ...
165
- except :
166
- transaction.rollback()
167
- else :
168
- transaction.commit()
169
- ```
170
-
171
- You can also use ` .transaction() ` as a function decorator on any async function:
172
-
173
- ``` python
174
- @database.transaction ()
175
- async def create_users (request ):
176
- ...
177
- ```
178
-
179
- Transaction blocks are managed as task-local state. Nested transactions
180
- are fully supported, and are implemented using database savepoints.
181
-
182
- ## Connecting and disconnecting
183
-
184
- You can control the database connect/disconnect, by using it as a async context manager.
185
-
186
- ``` python
187
- async with Database(DATABASE_URL ) as database:
188
- ...
189
- ```
190
-
191
- Or by using explicit connection and disconnection:
192
-
193
- ``` python
194
- database = Database(DATABASE_URL )
195
- await database.connect()
196
- ...
197
- await database.disconnect()
198
- ```
199
-
200
- If you're integrating against a web framework, then you'll probably want
201
- to hook into framework startup or shutdown events. For example, with
202
- [ Starlette] [ starlette ] you would use the following:
203
-
204
- ``` python
205
- @app.on_event (" startup" )
206
- async def startup ():
207
- await database.connect()
208
-
209
- @app.on_event (" shutdown" )
210
- async def shutdown ():
211
- await database.disconnect()
212
- ```
213
-
214
- ## Connection options
215
-
216
- The PostgreSQL and MySQL backends provide a few connection options for SSL
217
- and for configuring the connection pool.
218
-
219
- ``` python
220
- # Use an SSL connection.
221
- database = Database(' postgresql://localhost/example?ssl=true' )
222
-
223
- # Use a connection pool of between 5-20 connections.
224
- database = Database(' mysql://localhost/example?min_size=5&max_size=20' )
225
- ```
226
-
227
- You can also use keyword arguments to pass in any connection options.
228
- Available keyword arguments may differ between database backends.
229
-
230
- ``` python
231
- database = Database(' postgresql://localhost/example' , ssl = True , min_size = 5 , max_size = 20 )
232
- ```
233
-
234
- ## Test isolation
235
-
236
- For strict test isolation you will always want to rollback the test database
237
- to a clean state between each test case:
238
-
239
- ``` python
240
- database = Database(DATABASE_URL , force_rollback = True )
241
- ```
242
-
243
- This will ensure that all database connections are run within a transaction
244
- that rollbacks once the database is disconnected.
245
-
246
- If you're integrating against a web framework you'll typically want to
247
- use something like the following pattern:
248
-
249
- ``` python
250
- if TESTING :
251
- database = Database(TEST_DATABASE_URL , force_rollback = True )
252
- else :
253
- database = Database(DATABASE_URL )
254
- ```
255
-
256
- This will give you test cases that run against a different database to
257
- the development database, with strict test isolation so long as you make sure
258
- to connect and disconnect to the database between test cases.
259
-
260
- For a lower level API you can explicitly create force-rollback transactions:
261
-
262
- ``` python
263
- async with database.transaction(force_rollback = True ):
264
- ...
265
- ```
266
-
267
- ## Migrations
268
-
269
- Because ` databases ` uses SQLAlchemy core, you can integrate with [ Alembic] [ alembic ]
270
- for database migration support.
271
-
272
- ``` shell
273
- $ pip install alembic
274
- $ alembic init migrations
275
- ```
276
-
277
- You'll want to set things up so that Alembic references the configured
278
- ` DATABASE_URL ` , and uses your table metadata.
279
-
280
- In ` alembic.ini ` remove the following line:
281
-
282
- ``` shell
283
- sqlalchemy.url = driver://user:pass@localhost/dbname
86
+ print (' High Scores:' , rows)
284
87
```
285
88
286
- In ` migrations/env.py ` , you need to set the `` 'sqlalchemy.url' `` configuration key,
287
- and the ` target_metadata ` variable. You'll want something like this:
288
-
289
- ``` python
290
- # The Alembic Config object.
291
- config = context.config
292
-
293
- # Configure Alembic to use our DATABASE_URL and our table definitions.
294
- # These are just examples - the exact setup will depend on whatever
295
- # framework you're integrating against.
296
- from myapp.settings import DATABASE_URL
297
- from myapp.tables import metadata
298
-
299
- config.set_main_option(' sqlalchemy.url' , str (DATABASE_URL ))
300
- target_metadata = metadata
301
-
302
- ...
303
- ```
304
-
305
- Note that migrations will use a standard synchronous database driver,
306
- rather than using the async drivers that ` databases ` provides support for.
307
-
308
- This will also be the case if you're using SQLAlchemy's standard tooling, such
309
- as using ` metadata.create_all(engine) ` to setup the database tables.
310
-
311
- ** Note for MySQL** :
312
-
313
- For MySQL you'll probably need to explicitly specify the ` pymysql ` dialect when
314
- using Alembic since the default MySQL dialect does not support Python 3.
89
+ Check out the documentation on [ making database queries] ( database_queries.md )
90
+ for examples of how to start using databases together with SQLAlchemy core expressions.
315
91
316
- If you're using the ` databases.DatabaseURL ` datatype, you can obtain this using
317
- ` DATABASE_URL.replace(dialect="pymysql") `
318
92
319
93
<p align =" center " >&mdash ; ⭐️ &mdash ; </p >
320
94
<p align =" center " ><i >Databases is <a href =" https://github.com/encode/databases/blob/master/LICENSE.md " >BSD licensed</a > code. Designed & built in Brighton, England.</i ></p >
0 commit comments