69
|
1 |
PgManager
|
|
2 |
=========
|
|
3 |
|
104
|
4 |
PgManager is higher level database adapter for Python and Postgres. There is also MyManager for MySQL. Both are part of `pydbkit <http://hg.devl.cz/pydbkit>`_.
|
69
|
5 |
|
|
6 |
PgManager offers following convenience functionality over psycopg:
|
|
7 |
|
|
8 |
* **Save and reuse database connection parameters**
|
|
9 |
|
|
10 |
- parameters are linked to uniquely named ConnectionInfo structure
|
|
11 |
|
|
12 |
- using this identifier, you can retrieve Connection or Cursor object at any time
|
|
13 |
(new database connection is established when needed)
|
|
14 |
|
|
15 |
* **Connection pooling**
|
|
16 |
|
|
17 |
- connections with same identifier are pooled and reused
|
|
18 |
|
|
19 |
* **Easy query using the with statement**
|
|
20 |
|
|
21 |
- just use cursor() method in with statement
|
|
22 |
|
|
23 |
- PgManager will get a connection from pool, make cursor and clean up when you're finished
|
|
24 |
|
|
25 |
* **Dictionary rows**
|
|
26 |
|
|
27 |
- cursor has additional methods like fetchall_dict(), which
|
|
28 |
returns OrderedDict row instead of ordinary list-like row
|
|
29 |
|
|
30 |
|
|
31 |
Basic usage
|
|
32 |
-----------
|
|
33 |
|
|
34 |
::
|
|
35 |
|
104
|
36 |
from pydbkit import pgmanager
|
69
|
37 |
|
|
38 |
pgm = pgmanager.get_instance()
|
|
39 |
pgm.create_conn(hostaddr='127.0.0.1', dbname='postgres', isolation_level='autocommit')
|
|
40 |
|
|
41 |
with pgm.cursor() as curs:
|
|
42 |
curs.execute('SELECT now() AS now')
|
|
43 |
row = curs.fetchone_dict()
|
|
44 |
print(row.now)
|
|
45 |
|
|
46 |
|
|
47 |
Advanced usage
|
|
48 |
--------------
|
|
49 |
|
|
50 |
Study this when you cannot go with basic usage and need to know what actually happens.
|
|
51 |
Look also into source code, there are many details described in docstrings::
|
|
52 |
|
|
53 |
# create new connection info, this will not connect yet
|
|
54 |
pgm.create_conn(name='thatdb', hostaddr='127.0.0.1', dbname='postgres')
|
|
55 |
|
|
56 |
# borrow connection from pool (it will connect to DB here and possibly fail)
|
|
57 |
conn = pgm.get_conn('thatdb')
|
|
58 |
|
|
59 |
try:
|
|
60 |
# do stuff on that connection
|
|
61 |
curs = conn.cursor()
|
|
62 |
curs.execute('SELECT now() AS now')
|
|
63 |
row = curs.fetchone_dict()
|
|
64 |
# don't forget to commit when not in autocommit mode
|
|
65 |
curs.connection.commit()
|
|
66 |
print(row.now)
|
|
67 |
finally:
|
|
68 |
# return connection back to pool
|
|
69 |
# Beware: name must be correct here, it'll not be checked!
|
|
70 |
pgm.put_conn(conn, 'thatdb')
|
|
71 |
|
|
72 |
# close all connections in pool
|
|
73 |
pgm.close_conn('thatdb')
|
|
74 |
|
|
75 |
|
|
76 |
Logging
|
|
77 |
-------
|
|
78 |
|
|
79 |
PgManager logs all queries before they are executed, exceptions while executing
|
|
80 |
queries and also notices.
|
|
81 |
Queries and exceptions are logged into 'pgmanager_sql' logger,
|
|
82 |
notices into 'pgmanager_notices'. You need to setup logging for
|
|
83 |
these loggers to send messages into file or elsewhere.
|
|
84 |
|
|
85 |
Notices are logged only from cursor() method.
|
|
86 |
If you are using get_conn() instead, you must call log_notices() directly.
|
|
87 |
|
|
88 |
|
|
89 |
Listen - Notify
|
|
90 |
---------------
|
|
91 |
|
|
92 |
PostgreSQL supports asynchronous messages from server to clients.
|
|
93 |
This adds little more complexity to client programs but saves a lot of polling.
|
|
94 |
|
|
95 |
You should not use connection info created by create_conn() for LISTEN queries.
|
|
96 |
It will work in basic case, but it will broke when you add some sort of parallelism.
|
|
97 |
|
|
98 |
Use create_conn_listen instead. It allows to copy connection info parameters directly from another connection info or set up new one::
|
|
99 |
|
|
100 |
# create connection info without pool and with initial query 'LISTEN CHAT;'
|
|
101 |
pgm.create_conn_listen(name='listenconn', channel='CHAT', copy_dsn='thatdb')
|
|
102 |
|
|
103 |
while not done:
|
|
104 |
notify = pgm.wait_for_notify('listenconn', timeout=5.0)
|
|
105 |
if notify:
|
|
106 |
print('NOTIFY:', notify)
|
|
107 |
else:
|
|
108 |
print('timeout')
|
|
109 |
|
|
110 |
pgm.close_conn('listenconn')
|
|
111 |
|
|
112 |
|
79
|
113 |
Timeouts
|
|
114 |
--------
|
|
115 |
|
|
116 |
In production, it's very important to set reasonable timeouts for both connection
|
|
117 |
and query execution. Application should not freeze when database server gets out of reach.
|
|
118 |
|
|
119 |
Both timeouts can be set using :meth:`create_conn`::
|
|
120 |
|
|
121 |
pgm.create_conn(host='127.0.0.1', dbname='test',
|
|
122 |
init_statement='SET statement_timeout TO 20000;', # in ms, so it's 20s
|
|
123 |
connect_timeout=20, # also 20s
|
|
124 |
isolation_level='autocommit')
|
|
125 |
|
|
126 |
|
69
|
127 |
Methods
|
|
128 |
-------
|
|
129 |
|
104
|
130 |
.. autoclass:: pydbkit.pgmanager.PgManager
|
69
|
131 |
:members:
|
|
132 |
:undoc-members:
|
|
133 |
|