4
4
Installation
5
5
------------
6
6
7
- :py:mod:`postgres` is available on `GitHub`_ and `PyPI`_::
7
+ :py:mod:`postgres` is available on `GitHub`_ and on `PyPI`_::
8
8
9
9
$ pip install postgres
10
10
15
15
Instantiate a :py:class:`Postgres` object when your application starts:
16
16
17
17
>>> from postgres import Postgres
18
- >>> db = Postgres("postgres://jdoe @localhost/testdb")
18
+ >>> db = Postgres("postgres://jrandom @localhost/testdb")
19
19
20
- Use it to run SQL statements:
20
+ Use :py:meth:`~postgres.Postgres.run` to run SQL statements:
21
21
22
- >>> db.execute ("CREATE TABLE foo (bar text)")
23
- >>> db.execute ("INSERT INTO foo VALUES ('baz')")
24
- >>> db.execute ("INSERT INTO foo VALUES ('buz')")
22
+ >>> db.run ("CREATE TABLE foo (bar text)")
23
+ >>> db.run ("INSERT INTO foo VALUES ('baz')")
24
+ >>> db.run ("INSERT INTO foo VALUES ('buz')")
25
25
26
- Use it to fetch all results :
26
+ Use :py:meth:`~postgres.Postgres.one` to fetch one result :
27
27
28
- >>> db.fetchall("SELECT * FROM foo ORDER BY bar")
29
- [{"bar": "baz"}, {"bar": "buz"}]
28
+ >>> db.one("SELECT * FROM foo ORDER BY bar")
29
+ {'bar': 'baz'}
30
+ >>> db.one("SELECT * FROM foo WHERE bar='blam'")
31
+ None
30
32
31
- Use it to fetch one result :
33
+ Use :py:meth:`~postgres.Postgres.rows` to fetch all results :
32
34
33
- >>> db.fetchone("SELECT * FROM foo ORDER BY bar")
34
- {"bar": "baz"}
35
- >>> db.fetchone("SELECT * FROM foo WHERE bar='blam'")
36
- None
35
+ >>> db.rows("SELECT * FROM foo ORDER BY bar")
36
+ [{'bar': 'baz'}, {'bar': 'buz'}]
37
+
38
+
39
+ Bind Parameters
40
+ +++++++++++++++
41
+
42
+ In case you're not familiar with bind parameters in DB-API 2.0, the basic idea
43
+ is that you put ``%(foo)s`` in your SQL strings, and then pass in a second
44
+ argument, a :py:class:`dict`, containing parameters that :py:mod:`psycopg2` (as
45
+ an implementation of DB-API 2.0) will bind to the query in a way that is safe
46
+ against SQL injection. (This is inspired by old-style Python string formatting,
47
+ but it is not the same.)
48
+
49
+ >>> db.one("SELECT * FROM foo WHERE bar=%(bar)s", {"bar": "baz"})
50
+ {'bar': 'baz'}
51
+
52
+ Never build SQL strings out of user input!
53
+
54
+ Always pass user input as bind parameters!
37
55
38
56
39
57
Context Managers
53
71
>>> with db.get_cursor() as cursor:
54
72
... cursor.execute("SELECT * FROM foo ORDER BY bar")
55
73
... cursor.fetchall()
56
- [{"bar": "baz"}, {"bar": "buz"}]
74
+ ...
75
+ [{'bar': 'baz'}, {'bar': 'buz'}]
57
76
58
77
A cursor you get from :py:func:`~postgres.Postgres.get_cursor` has
59
78
:py:attr:`autocommit` turned on for its connection, so every call you make
65
84
... txn.execute("INSERT INTO foo VALUES ('blam')")
66
85
... txn.execute("SELECT * FROM foo ORDER BY bar")
67
86
... txn.fetchall()
68
- [{"bar": "baz"}, {"bar": "blam"}, {"bar": "buz"}]
69
87
...
70
- ... db.fetchall("SELECT * FROM foo ORDER BY bar")
71
- [{"bar": "baz"}, {"bar": "buz"}]
88
+ [{'bar': 'baz'}, {'bar': 'blam'}, {'bar': 'buz'}]
89
+
90
+ Note that other calls won't see the changes on your transaction until the end
91
+ of your code block, when the context manager commits the transaction::
92
+
93
+ >>> with db.get_transaction() as txn:
94
+ ... txn.execute("INSERT INTO foo VALUES ('blam')")
95
+ ... db.rows("SELECT * FROM foo ORDER BY bar")
72
96
...
73
- ... db.fetchall("SELECT * FROM foo ORDER BY bar")
74
- [{"bar": "baz"}, {"bar": "blam"}, {"bar": "buz"}]
97
+ [{'bar': 'baz'}, {'bar': 'buz'}]
98
+ >>> db.rows("SELECT * FROM foo ORDER BY bar")
99
+ [{'bar': 'baz'}, {'bar': 'blam'}, {'bar': 'buz'}]
75
100
76
101
The :py:func:`~postgres.Postgres.get_transaction` manager gives you a cursor
77
102
with :py:attr:`autocommit` turned off on its connection. If the block under
85
110
... cursor = connection.cursor()
86
111
... cursor.execute("SELECT * FROM foo ORDER BY bar")
87
112
... cursor.fetchall()
88
- [{"bar": "baz"}, {"bar": "buz"}]
113
+ ...
114
+ [{'bar': 'baz'}, {'bar': 'buz'}]
89
115
90
116
A connection gotten in this way will have :py:attr:`autocommit` turned off, and
91
117
it'll never be implicitly committed otherwise. It'll actually be rolled back
@@ -155,18 +181,35 @@ class Postgres(object):
155
181
:param int maxconn: The minimum size of the connection pool
156
182
157
183
This is the main object that :py:mod:`postgres` provides, and you should
158
- have one instance per process for each database your process needs to talk
159
- to. When instantiated, this object creates a `thread-safe connection pool
184
+ have one instance per process for each PostgreSQL database your process
185
+ wants to talk to using this library. When instantiated, this object creates
186
+ a `thread-safe connection pool
160
187
<http://initd.org/psycopg/docs/pool.html#psycopg2.pool.ThreadedConnectionPool>`_,
161
188
which opens :py:attr:`minconn` connections immediately, and up to
162
189
:py:attr:`maxconn` according to demand. The fundamental value of a
163
190
:py:class:`~postgres.Postgres` instance is that it runs everything through
164
191
its connection pool.
165
192
193
+ The names in our simple API, :py:meth:`~postgres.Postgres.run`,
194
+ :py:meth:`~postgres.Postgres.one`, and :py:meth:`~postgres.Postgres.rows`,
195
+ were chosen to be short and memorable, and to not conflict with the DB-API
196
+ 2.0 :py:meth:`execute`, :py:meth:`fetchone`, and :py:meth:`fetchall`
197
+ methods, which have slightly different semantics (under DB-API 2.0 you call
198
+ :py:meth:`execute` on a cursor and then call one of the :py:meth:`fetch*`
199
+ methods on the same cursor to retrieve rows; with our simple API there is
200
+ no second :py:meth:`fetch` step). The context managers on this class are
201
+ named starting with :py:meth:`get_` to set them apart from the simple-case
202
+ API. Note that when working inside a block under one of the context
203
+ managers, you're using DB-API 2.0 (:py:meth:`execute` + :py:meth:`fetch*`),
204
+ not our simple API (:py:meth:`~postgres.Postgres.run` /
205
+ :py:meth:`~postgres.Postgres.one` / :py:meth:`~postgres.Postgres.rows`).
206
+
166
207
Features:
167
208
168
209
- Get back unicode instead of bytestrings.
169
210
211
+ >>> import postgres
212
+ >>> db = postgres.Postgres("postgres://jrandom@localhost/test")
170
213
171
214
"""
172
215
@@ -179,39 +222,53 @@ def __init__(self, url, minconn=1, maxconn=10):
179
222
, connection_factory = Connection
180
223
)
181
224
182
- def execute (self , sql , parameters = None ):
183
- """Execute the query and discard any results.
225
+ def run (self , sql , parameters = None ):
226
+ """Execute a query and discard any results.
184
227
185
228
:param unicode sql: the SQL statement to execute
186
229
:param parameters: the bind parameters for the SQL statement
187
- :type parameters: tuple or dict
230
+ :type parameters: dict or tuple
188
231
:returns: :py:const:`None`
189
232
233
+ >>> db.run("CREATE TABLE foo (bar text)")
234
+ >>> db.run("INSERT INTO foo VALUES ('baz')")
235
+ >>> db.run("INSERT INTO foo VALUES ('buz')")
236
+
190
237
"""
191
238
with self .get_cursor () as cursor :
192
239
cursor .execute (sql , parameters )
193
240
194
- def fetchone (self , sql , parameters = None ):
195
- """Execute the query and return a single result.
241
+ def one (self , sql , parameters = None ):
242
+ """Execute a query and return a single result.
196
243
197
244
:param unicode sql: the SQL statement to execute
198
245
:param parameters: the bind parameters for the SQL statement
199
- :type parameters: tuple or dict
246
+ :type parameters: dict or tuple
200
247
:returns: :py:class:`dict` or :py:const:`None`
201
248
249
+ >>> row = db.one("SELECT * FROM foo WHERE bar='baz'"):
250
+ >>> print(row["bar"])
251
+ baz
252
+
202
253
"""
203
254
with self .get_cursor () as cursor :
204
255
cursor .execute (sql , parameters )
205
256
return cursor .fetchone ()
206
257
207
- def fetchall (self , sql , parameters = None ):
208
- """Execute the query and return all results .
258
+ def rows (self , sql , parameters = None ):
259
+ """Execute a query and return all resulting rows .
209
260
210
261
:param unicode sql: the SQL statement to execute
211
262
:param parameters: the bind parameters for the SQL statement
212
- :type parameters: tuple or dict
263
+ :type parameters: dict or tuple
213
264
:returns: :py:class:`list` of :py:class:`dict`
214
265
266
+ >>> for row in db.rows("SELECT bar FROM foo"):
267
+ ... print(row["bar"])
268
+ ...
269
+ baz
270
+ buz
271
+
215
272
"""
216
273
with self .get_cursor () as cursor :
217
274
cursor .execute (sql , parameters )
@@ -223,10 +280,15 @@ def get_cursor(self, *a, **kw):
223
280
224
281
This is what :py:meth:`~postgres.Postgres.execute`,
225
282
:py:meth:`~postgres.Postgres.fetchone`, and
226
- :py:meth:`~postgres.Postgres.fetchall` use under the hood. It's
227
- probably less directly useful than
228
- :py:meth:`~postgres.Postgres.get_transaction` and
229
- :py:meth:`~postgres.Postgres.get_connection`.
283
+ :py:meth:`~postgres.Postgres.fetchall` use under the hood. You might
284
+ use it if you want to access `cursor attributes
285
+ <http://initd.org/psycopg/docs/cursor.html>`_, for example.
286
+
287
+ >>> with db.get_cursor() as cursor:
288
+ ... cursor.execute("SELECT * FROM foo")
289
+ ... cursor.rowcount
290
+ ...
291
+ 2
230
292
231
293
"""
232
294
return CursorContextManager (self .pool , * a , ** kw )
@@ -237,7 +299,15 @@ def get_transaction(self, *a, **kw):
237
299
238
300
Use this when you want a series of statements to be part of one
239
301
transaction, but you don't need fine-grained control over the
240
- transaction.
302
+ transaction. If your code block inside the :py:obj:`with` statement
303
+ raises an exception, the transaction will be rolled back. Otherwise,
304
+ it'll be committed.
305
+
306
+ >>> with db.get_transaction() as txn:
307
+ ... txn.execute("SELECT * FROM foo")
308
+ ... txn.fetchall()
309
+ ...
310
+ [{'bar': 'baz'}, {'bar': 'buz'}]
241
311
242
312
"""
243
313
return TransactionContextManager (self .pool , * a , ** kw )
@@ -250,15 +320,22 @@ def get_connection(self):
250
320
otherwise need full control, for example, to do complex things with
251
321
transactions.
252
322
323
+ >>> with db.get_connection() as connection:
324
+ ... cursor = connection.cursor()
325
+ ... cursor.execute("SELECT * FROM foo")
326
+ ... cursor.fetchall()
327
+ ...
328
+ [{'bar': 'baz'}, {'bar': 'buz'}]
329
+
253
330
"""
254
331
return ConnectionContextManager (self .pool )
255
332
256
333
257
334
class Connection (psycopg2 .extensions .connection ):
258
335
"""This is a subclass of :py:class:`psycopg2.extensions.connection`.
259
336
260
- This class is used as the :py:attr:`connection_factory` for the connection
261
- pool in :py:class:`Postgres` . Here are the differences from the base class:
337
+ :py: class:`Postgres` uses this class as the :py:attr:`connection_factory`
338
+ for its connection pool . Here are the differences from the base class:
262
339
263
340
- We set :py:attr:`autocommit` to :py:const:`True`.
264
341
- We set the client encoding to ``UTF-8``.
0 commit comments