dbpy是一個python寫的數據庫CURD人性化api庫。借鑑了 webpy db 和 drupal database 的設計。 若是喜歡 tornado db 或者 webpy db這類輕巧的db庫,或者想發揮原生SQL優點,那麼值得一試。css
Contentshtml
從github上fork下來,終端執行下面命令:python
cd dbpy # the path to the project python setup.py install
Notemysql
安裝前先安裝 MySQLdb (MySQL-python) 依賴python庫git
下載後終端執行:github
cd dbpy # the path to the project python setup.py develop
在 Python 2.7.x 測試開發web
先提醒下模塊使用單例模式。因此api相對比較好使。sql
config = { 'passwd': 'test', 'user': 'test', 'host': 'localhost', 'db': 'test', 'max_idle' : 5*60 } db.setup(config, minconn=5, maxconn=10, adapter='mysql', key='defalut', slave=False)
config: | 是數據庫鏈接參數,能夠傳入MySQLDB#connect接口中全部的可選參數。 其中``max_idle`` 相對是mysql服務端 connect_timeout配置,默認10秒。 |
---|---|
minconn: | 爲當前數據庫鏈接池保持最小鏈接池,默認爲5 |
maxconn: | 爲當前數據庫鏈接池最大鏈接池,默認爲10 |
adapter: | 爲適配器名,當前只支持 mysql |
key: | 是數據庫的標識符,默認爲 default |
slave: | 若是爲true那麼當前的數據庫將會註冊爲讀數據庫。若是你沒有作讀寫分離,只有一個數據庫用來讀寫,那麼setup一次就好,這樣就能夠讀寫。 |
config = { 'passwd': 'test', 'user': 'test', 'host': 'localhost', 'db': 'test', 'max_idle' : 5*60 } db.setup(config, key='test') config['host'] = 'test.slave' # 此次setup將會把key標記爲僅可寫,就是在後面用api時,制定到當前key的數據庫會作數據分離 db.setup(config, key='test', slave=True) config['host'] = 'test.slave2' # 再加入一個slave數據庫 db.setup(config, key='test', slave=True) config['host'] = 'host2' config['db'] = 'social' # 再加入一個數據庫 db.setup(config, key='social', slave=True)
query用於raw sql的查詢語言。若是有更新數據請用execute.數據庫
query(sql, args=None, many=None, as_dict=False, key='default'):api
sql: | mysql的格式化raw sql |
---|---|
args: | 能夠爲元組和list,是sql格式化預處理的輸入 |
many: | 若是指定爲大於零的整數將會使用fetchmany語句,並返回對象將會是迭代器.不然api調用fetchall返回結果. |
as_dict: | 若是爲 true將會返回字典行,不然返回元組行。 |
key: | 用於指定使用那個數據庫。 |
print db.query('SELECT 1') # > ((1L,),) # use social db print db.query('SELECT 1', key='social') # > ((1L,),) print db.query('SELECT * FROM users WHERE uid=%s and name=%s', (1, 'user_1')) # > ((1L, u'user_1'),) # Wanna return dict row print db.query('SELECT * FROM users WHERE uid=%s and name=%s', (1, 'user_1'), as_dict=True) # > ({'uid': 1L, 'name': u'user_1'},) # Use fetchmany(many) then yeild, Return generator res = db.query('SELECT * FROM users WHERE uid=%s and name=%s', (1, 'user_1'), many=5, as_dict=True) print res print res.next() # > <generator object _yield at 0x7f818f4b6820> # > {'uid': 1L, 'name': u'user_1'}
execute用於raw sql的更新語言。 execute(sql, args=None, key='default'):
sql: | mysql的格式化raw sql |
---|---|
args: | 能夠爲元組和list,是sql格式化預處理的輸入.以下面例子insert語句values有多個插入時,調用 executemany |
key: | 用於指定使用那個數據庫。 |
返回規範:
對於insert 將會返回 last_insert_id, 其餘更新語句返回rowcount
db.execute('DROP TABLE IF EXISTS `users`') db.execute("""CREATE TABLE `users` ( `uid` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL, PRIMARY KEY (`uid`))""") # insert語句插入多個value,注意這樣寫將會調用executemany,你懂的,就是封裝了多條execute的玩意 db.execute('INSERT INTO users VALUES(%s, %s)', [(10, 'execute_test'), (9, 'execute_test')]) # > 9 db.execute('DELETE FROM users WHERE name=%s', ('execute_test',)) # > 2 # use social db db.execute('delete from events where created_at<%s', (expired, ), key='social') # > 10
select用於構建select 查詢語言。
select(table, key='default'):
table: | 選定表 |
---|---|
key: | 用於指定使用那個數據庫。 |
db.select('users') # > SELECT * FROM `users`
db.select('users').fields('uid', 'name') # > SELECT `uid`, `name` FROM `users`
在構建好查詢條語句後使用execute api能夠返回結果。
execute(many=None, as_dict=False):
many: | 若是指定爲大於零的整數將會使用fetchmany語句,並返回對象將會是迭代器.不然api調用fetchall返回結果. |
---|---|
as_dict: | 若是爲 true將會返回字典行,不然返回元組行。 |
q = db.select('users').fields('uid', 'name') res = q.execute() print res # > ((1L, u'user_1'), (2L, u'user_2'), (3L, u'user_3'), (4L, u'user_4'), (5L, None)) res = q.execute(many=2, as_dict=True) print res print res.next() # > <generator object _yield at 0x7f835825e820> # > {'uid': 1L, 'name': u'user_1'}
上面已經學會如何作簡單的查詢,那麼如何組件條件查詢。這裏將會重點講述condition方法如何構建各類查詢條件。
condition(field, value=None, operator=None):
field: | 是條件限制的表字段 |
---|---|
value: | 是字段的條件值, 若是炸路額, oprator都不指定就是 "field is null" |
operator: | 默承認能是等於操做符號, 可選的操做符號有 BETWEEN, IN, NOT IN, EXISTS, NOT EXISTS, IS NULL, IS NOT NULL, LIKE, NOT LIKE, =, <, >, >=, <=, <>等 |
在全部的select,update, delete查詢中多個默認的condition將會是and條件組合。
db.select('users').condition('uid', 1) # condition('uid', 1, '=') # > SELECT * FROM `users` # > WHERE `uid` = %s
db.select('users').condition('uid', (1, 3)) # condition('uid', [1, 3]) 同樣 # > SELECT * FROM `users` # > WHERE `uid` IN (%s, %s)
db.select('users').condition('uid', (1, 3), 'between') # > SELECT * FROM `users` # > WHERE `uid` BETWEEN %s AND %s
multi condition
db.select('users').condition('uid', (1, 3), 'between') # > SELECT * FROM `users` # > WHERE `uid` BETWEEN %s AND %s
or_cond = db.or_().condition('uid', 1).condition('name', 'blabla') db.select('users').condition(or_cond).condition('uid', 1, '<>') # > SELECT * FROM `users` # > WHERE ( `uid` = %s OR `name` = %s ) AND `uid` <> %s
db.select('users').order_by('name') # > SELECT * FROM `users` # > ORDER BY `name` db.select('users').order_by('name', 'DESC') # > SELECT * FROM `users` # > ORDER BY `name` DESC db.select('users').order_by('name', 'DESC').order_by('uid') # > SELECT * FROM `users` # > ORDER BY `name` DESC, `uid`
db.select('users').order_by('name') # > SELECT * FROM `users` # > ORDER BY `name` db.select('users').order_by('name', 'DESC') # > SELECT * FROM `users` # > ORDER BY `name` DESC db.select('users').order_by('name', 'DESC').order_by('uid') # > SELECT * FROM `users` # > ORDER BY `name` DESC, `uid`
db.select('users').group_by('name', 'uid') # > SELECT * FROM `users` # > GROUP BY `name`, `uid`
db.select('users').limit(2).offset(5) # > SELECT * FROM `users` # > LIMIT 2 OFFSET 5
db.select('users').is_null('name').condition('uid', 5) # > SELECT * FROM `users` # > WHERE `name` IS NULL AND `uid` = %s db.select('users').is_not_null('name').condition('uid', 5) # > SELECT * FROM `users` # > WHERE `name` IS NOT NULL AND `uid` = %s db.select('users').condition('name', None) # > SELECT * FROM `users` # > WHERE `name` IS NULL
使用 db.and_(), db.or_() 能夠構建and或or粘合的條件組合。
or_cond = db.or_().condition('field1', 1).condition('field2', 'blabla') and_cond = db.and_().condition('field3', 'what').condition('field4', 'then?') print db.select('table_name').condition(or_cond).condition(and_cond) # > SELECT * FROM `table_name` # > WHERE ( `field1` = %s OR `field2` = %s ) AND ( `field3` = %s AND `field4` = %s )
若是你須要使用 count sum之類的集聚函數,那麼使用 Expr構建字段吧。
from db import expr db.select('users').fields(expr('count(*)')) # > SELECT count(*) FROM `users` db.select('users').fields(expr('count(uid)', 'total')) # > SELECT count(uid) AS `total` FROM `users`
insert用於構建insert into的sql語句。
insert(table, key='default'):
table: | 選定表 |
---|---|
key: | 用於指定使用那個數據庫。 |
q = db.insert('users').values((10, 'test_insert')) # > INSERT INTO `users` VALUES(%s, %s) print q._values # > [(10, 'test_insert')] q = db.insert('users').fields('name').values({'name': 'insert_1'}).values(('insert_2',)) # > INSERT INTO `users` (`name`) VALUES(%s) print q._values # > [('insert_1',), ('insert_2',)]
構建好執行execute會執行數據庫插入,execute返回的是last insert id:
print q.execute() # > 2
update用於構建update的sql語句
update(table, key='default'):
table: | 選定表 |
---|---|
key: | 用於指定使用那個數據庫。 |
update 主要可用的方法是mset和set, mset:
mset: | 傳入的是字典,用於一次set多個表屬性 |
---|---|
set(column, value): | 只能設置一個屬性,能夠屢次使用 |
構建條件codition前面已經講述了。請參考 select
db.update('users').mset({'name':None, 'uid' : 12}).condition('name','user_1') # > UPDATE `users` SET `name` = %s, `uid` = %s WHERE `name` = %s q = (db.update('users').set('name', 'update_test').set('uid', 12) .condition('name', 'user_2').condition('uid', 2)) # .execute() print q.to_sql() # > UPDATE `users` SET `name` = %s, `uid` = %s WHERE `name` = %s AND `uid` = %s
構建好執行execute會執行數據庫插入,execute返回的是更新的 rowcount:
print q.execute() # > 2
由於你可能但願限制更新幾條。那麼可使用limit
db.update('users').mset({'name':None, 'uid' : 12}).condition('name','user_1').limit(5) # > UPDATE `users` SET `name` = %s, `uid` = %s WHERE `name` = %s LIMIT 5
delete
delete 用於構建delete from的sql語句。
delete(table, key='default'):
table: | 選定表 |
---|---|
key: | 用於指定使用那個數據庫。 |
構建條件codition前面已經講述了。請參考 select
db.delete('users').condition('name','user_1') # > DELETE FROM `users` WHERE `name` = %s
構建好執行execute會執行數據庫插入,execute返回的是刪除的 rowcount:
print q.execute() # > 2
db.insert, db.update, db.delete 返回的對象均可以使用 to_sql 或者__str__ 來查看構建成的sql語句。
q = (db.update('users').set('name', 'update_test').set('uid', 12) .condition('name', 'user_2').condition('uid', 2)) print q.to_sql() print q # > UPDATE `users` SET `name` = %s, `uid` = %s WHERE `name` = %s AND `uid` = %s
transaction(table, key='default'):
table: | 選定表 |
---|---|
key: | 用於指定使用那個數據庫。 |
對於事務,這裏比較簡單的實現。要麼所有執行,要麼所有不作,沒有作保存點。
# with context with db.transaction() as t: t.delete('users').condition('uid', 1).execute() (t.update('users').mset({'name':None, 'uid' : 12}) .condition('name','user_1').execute()) # 普通用法 t = db.transaction() t.begin() t.delete('users').condition('uid', 1).execute() (t.update('users').mset({'name':None, 'uid' : 12}) .condition('name','user_1').execute()) #這裏將會提交,若是失敗將會rollback t.commit()
Note
使用 begin必定要結合commit方法,否則可能鏈接不會返還鏈接池。建議用 with 語句。
這裏將會講述最簡單的orm構建技巧, 詳細參考 samples
import model from orm import Backend import db db.setup({ 'host': 'localhost', 'user': 'test', 'passwd': 'test', 'db': 'blog'}) user = Backend('user').find_by_username('username') if user and user.check('password'): print 'auth' user = model.User('username', 'email', 'real_name', 'password', 'bio', 'status', 'role') if Backend('user').create(user): print 'fine' user = Backend('user').find(12) user.real_name = 'blablabla....' if Backend('user').save(user): print 'user saved' if Backend('user').delete(user): print 'delete user failed' post = model.Post('title', 'slug', 'description', 'html', 'css', 'js', 'category', 'status', 'comments', 'author') if not Backend('post').create(post): print 'created failed'
當前只支持mysql適配驅動,由於我的並不熟悉其餘關聯數據庫,dbpy的設計比較靈活,因此若是有高手能夠嘗試寫寫其餘數據庫適配,仿照 db/mysql目錄 若是寫pgsql的適配應該不會多餘800行代碼。
對於構建orm框架方面,從我的來說,更喜歡原生SQL,也不打算再造一個orm輪子。從設計和實現來講,dbpy是爲了更好的發揮原生SQL優點和簡單靈活。
我的一些想法: