44Installation
55------------
66
7- :py:mod:`postgres` is available on `GitHub`_ and `PyPI`_::
7+ :py:mod:`postgres` is available on `GitHub`_ and on `PyPI`_::
88
99 $ pip install postgres
1010
1515Instantiate a :py:class:`Postgres` object when your application starts:
1616
1717 >>> from postgres import Postgres
18- >>> db = Postgres("postgres://jdoe @localhost/testdb")
18+ >>> db = Postgres("postgres://jrandom @localhost/testdb")
1919
20- Use it to run SQL statements:
20+ Use :py:meth:`~postgres.Postgres.run` to run SQL statements:
2121
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')")
2525
26- Use it to fetch all results :
26+ Use :py:meth:`~postgres.Postgres.one` to fetch one result :
2727
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
3032
31- Use it to fetch one result :
33+ Use :py:meth:`~postgres.Postgres.rows` to fetch all results :
3234
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!
3755
3856
3957Context Managers
5371 >>> with db.get_cursor() as cursor:
5472 ... cursor.execute("SELECT * FROM foo ORDER BY bar")
5573 ... cursor.fetchall()
56- [{"bar": "baz"}, {"bar": "buz"}]
74+ ...
75+ [{'bar': 'baz'}, {'bar': 'buz'}]
5776
5877A cursor you get from :py:func:`~postgres.Postgres.get_cursor` has
5978:py:attr:`autocommit` turned on for its connection, so every call you make
6584 ... txn.execute("INSERT INTO foo VALUES ('blam')")
6685 ... txn.execute("SELECT * FROM foo ORDER BY bar")
6786 ... txn.fetchall()
68- [{"bar": "baz"}, {"bar": "blam"}, {"bar": "buz"}]
6987 ...
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")
7296 ...
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'}]
75100
76101The :py:func:`~postgres.Postgres.get_transaction` manager gives you a cursor
77102with :py:attr:`autocommit` turned off on its connection. If the block under
85110 ... cursor = connection.cursor()
86111 ... cursor.execute("SELECT * FROM foo ORDER BY bar")
87112 ... cursor.fetchall()
88- [{"bar": "baz"}, {"bar": "buz"}]
113+ ...
114+ [{'bar': 'baz'}, {'bar': 'buz'}]
89115
90116A connection gotten in this way will have :py:attr:`autocommit` turned off, and
91117it'll never be implicitly committed otherwise. It'll actually be rolled back
@@ -155,18 +181,35 @@ class Postgres(object):
155181 :param int maxconn: The minimum size of the connection pool
156182
157183 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
160187 <http://initd.org/psycopg/docs/pool.html#psycopg2.pool.ThreadedConnectionPool>`_,
161188 which opens :py:attr:`minconn` connections immediately, and up to
162189 :py:attr:`maxconn` according to demand. The fundamental value of a
163190 :py:class:`~postgres.Postgres` instance is that it runs everything through
164191 its connection pool.
165192
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+
166207 Features:
167208
168209 - Get back unicode instead of bytestrings.
169210
211+ >>> import postgres
212+ >>> db = postgres.Postgres("postgres://jrandom@localhost/test")
170213
171214 """
172215
@@ -179,39 +222,53 @@ def __init__(self, url, minconn=1, maxconn=10):
179222 , connection_factory = Connection
180223 )
181224
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.
184227
185228 :param unicode sql: the SQL statement to execute
186229 :param parameters: the bind parameters for the SQL statement
187- :type parameters: tuple or dict
230+ :type parameters: dict or tuple
188231 :returns: :py:const:`None`
189232
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+
190237 """
191238 with self .get_cursor () as cursor :
192239 cursor .execute (sql , parameters )
193240
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.
196243
197244 :param unicode sql: the SQL statement to execute
198245 :param parameters: the bind parameters for the SQL statement
199- :type parameters: tuple or dict
246+ :type parameters: dict or tuple
200247 :returns: :py:class:`dict` or :py:const:`None`
201248
249+ >>> row = db.one("SELECT * FROM foo WHERE bar='baz'"):
250+ >>> print(row["bar"])
251+ baz
252+
202253 """
203254 with self .get_cursor () as cursor :
204255 cursor .execute (sql , parameters )
205256 return cursor .fetchone ()
206257
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 .
209260
210261 :param unicode sql: the SQL statement to execute
211262 :param parameters: the bind parameters for the SQL statement
212- :type parameters: tuple or dict
263+ :type parameters: dict or tuple
213264 :returns: :py:class:`list` of :py:class:`dict`
214265
266+ >>> for row in db.rows("SELECT bar FROM foo"):
267+ ... print(row["bar"])
268+ ...
269+ baz
270+ buz
271+
215272 """
216273 with self .get_cursor () as cursor :
217274 cursor .execute (sql , parameters )
@@ -223,10 +280,15 @@ def get_cursor(self, *a, **kw):
223280
224281 This is what :py:meth:`~postgres.Postgres.execute`,
225282 :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
230292
231293 """
232294 return CursorContextManager (self .pool , * a , ** kw )
@@ -237,7 +299,15 @@ def get_transaction(self, *a, **kw):
237299
238300 Use this when you want a series of statements to be part of one
239301 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'}]
241311
242312 """
243313 return TransactionContextManager (self .pool , * a , ** kw )
@@ -250,15 +320,22 @@ def get_connection(self):
250320 otherwise need full control, for example, to do complex things with
251321 transactions.
252322
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+
253330 """
254331 return ConnectionContextManager (self .pool )
255332
256333
257334class Connection (psycopg2 .extensions .connection ):
258335 """This is a subclass of :py:class:`psycopg2.extensions.connection`.
259336
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:
262339
263340 - We set :py:attr:`autocommit` to :py:const:`True`.
264341 - We set the client encoding to ``UTF-8``.
0 commit comments