Package: dbpy
dbpy is database abstration layer wrote by python. The design is inspired bywebpy dbanddrupal database. If like the simple db abstration layer liketornado dborwebpy db, it is worth to try.中文|chinesechangesAdd pymysql adapterInstall the extension with the following command:$ easy_install pymysqlor alternatively if you have pip installed:$ pip install pymysqlFeatuessilmple and flexiblegraceful and useful sql query builder.thread-safe connection poolsupports read/write master-slave modesupports transactionThe Projects use dbpyLilac (Distributed Scheduler Task System)ContentschangesFeatuesThe Projects use dbpyInstallDevelopmentCompatibilityDB APIsetupqueryexecuteselectselect allspecific columnsexecuteConditionsimpleinbetweenmulti conditionor conditionorder bydistinctgroup bylimit and offsetnull conditioncomplex conditionsexprinsertupdatelimitdeleteto_sql and strtransactionsimple ormFutureLICENSEInstallInstall the extension with the following command:$ easy_install dbpyor alternatively if you have pip installed:$ pip install dbpyor clone it form github then run the command in shell:cddb# the path to the projectpythonsetup.pyinstallDevelopmentFork or download it, then run:cddb# the path to the projectpythonsetup.pydevelopCompatibilityBuilt and tested under Python 2.7+DB APIHave a look:config={'passwd':'test','user':'test','host':'localhost','db':'test','max_idle':5*60}db.setup(config,minconn=5,maxconn=10,adapter='mysql',key='default',slave=False)db.execute('show tables')setupconfig:the connection basic config, the all of arguements of MySQLDB#connect is acceptable。 themax_idleis the connect timeout setting that is used to reconnection when connection is timeout, default is 10 seconds.minconn:the minimum connections for the connection pool, default is 5.maxconn:the maximum connections for the connection pool, default is 10.adapter:the database driver adapter name, currently supports mysql (MySQLdb, pymysql) only.key:the database idenfify for database,  default database is “default”slave:if set to true, the database will be register as a slave database. make sure you setup a master firstly.config={'passwd':'test','user':'test','host':'localhost','db':'test','max_idle':5*60}db.setup(config,key='test')config['host']='test.slave'# set a slave, and now the master can only to writedb.setup(config,key='test',slave=True)config['host']='test.slave2'# add more slave for 'test'db.setup(config,key='test',slave=True)config['host']='host2'config['db']='social'# set another databasedb.setup(config,key='social',slave=True)queryquery api is used for reading database operation, like select…, show tables, if you wanna update your database please use execute api.query(sql, args=None, many=None, as_dict=False, key=’default’):sql:the raw sqlargs:the args for sql arguement to prepare execute.many:when set to a greater zero integer, it will use fetchmany then yield return a generator, otherwise a list.as_dict:when set to true, query api will return the database result as dict row, otherwise tuple row.key:the idenfify of database.printdb.query('SELECT 1')# > ((1L,),)# use social dbprintdb.query('SELECT 1',key='social')# > ((1L,),)printdb.query('SELECT * FROM users WHERE uid=%sand name=%s',(1,'user_1'))# > ((1L, u'user_1'),)# Wanna return dict rowprintdb.query('SELECT * FROM users WHERE uid=%sand name=%s',(1,'user_1'),as_dict=True)# > ({'uid': 1L, 'name': u'user_1'},)# Use fetchmany(many) then yeild, Return generatorres=db.query('SELECT * FROM users WHERE uid=%sand name=%s',(1,'user_1'),many=5,as_dict=True)printresprintres.next()# > <generator object _yield at 0x7f818f4b6820># > {'uid': 1L, 'name': u'user_1'}executethe api is used for writing database operation, like insert, update, delete.. if you wanna read query your database please use query api.execute(sql, args=None, key=’default’):sql:the raw sqlargs:the args for sql arguement to prepare execute.key:the idenfify of database.Return:it returns last_insert_id when sql is insert statement, otherwise rowcountdb.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`))""")# when inset mutil-values，the api will call executemanydb.execute('INSERT INTO users VALUES(%s,%s)',[(10,'execute_test'),(9,'execute_test')])# > 9db.execute('DELETE FROM users WHERE name=%s',('execute_test',))# > 2# use social dbdb.execute('delete from events where created_at<%s',(expired,),key='social')# > 10selectthe api is used for select sql database query.select(table, key=’default’):table:the table namekey:the idenfify of databaseselect alldb.select('users')# > SELECT * FROM `users`specific columnsdb.select('users').fields('uid','name')# > SELECT `uid`, `name` FROM `users`executewhen you already build your sql, try execute api to fetch your database result.execute(many=None, as_dict=False):many:when set to a greater zero integer, it will use fetchmany then yield return a generator, otherwise a list.as_dict:when set to true, query api will return the database result as dict row, otherwise tuple row.q=db.select('users').fields('uid','name')res=q.execute()printres# > ((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)printresprintres.next()# > <generator object _yield at 0x7f835825e820># > {'uid': 1L, 'name': u'user_1'}ConditionIt is time to try more complex select query.condition(field, value=None, operator=None):field:the field of tablevalue:the value of field, defaul is None (“field is null”)operator:the where operator like BETWEEN, IN, NOT IN, EXISTS, NOT EXISTS, IS NULL, IS NOT NULL, LIKE, NOT LIKE, =, <, >, >=, <=, <> and so on.simpledb.select('users').condition('uid',1)# condition('uid', 1, '=')# > SELECT * FROM `users`# > WHERE  `uid` = %sindb.select('users').condition('uid',(1,3))# condition('uid', [1, 3]) 一样# > SELECT * FROM `users`# > WHERE  `uid` IN  (%s, %s)betweendb.select('users').condition('uid',(1,3),'between')# > SELECT * FROM `users`# > WHERE  `uid` BETWEEN %s AND %smulti conditiondb.select('users').condition('uid',1).condition('name','blabla')# > SELECT * FROM `users`# > WHERE  `uid` = %s AND `name` = %sor conditionor_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` <> %sorder bydb.select('users').order_by('name')# > SELECT * FROM `users`# > ORDER BY `name`db.select('users').order_by('name','DESC')# > SELECT * FROM `users`# > ORDER BY `name` DESCdb.select('users').order_by('name','DESC').order_by('uid')# > SELECT * FROM `users`# > ORDER BY `name` DESC, `uid`distinctdb.select('users').distinct().condition('uid',1)# > SELECT DISTINCT * FROM `users`# > WHERE  `uid` = %sdb.select('users').fields('uid','name').distinct().condition('uid',1)# > SELECT DISTINCT `uid`, `name` FROM `users`# > WHERE  `uid` = %sgroup bydb.select('users').group_by('name','uid')# > SELECT * FROM `users`# > GROUP BY `name`, `uid`limit and offsetdb.select('users').limit(2).offset(5)# > SELECT * FROM `users`# > LIMIT 2 OFFSET 5null conditiondb.select('users').is_null('name').condition('uid',5)# > SELECT * FROM `users`# > WHERE  `name` IS NULL  AND `uid` = %sdb.select('users').is_not_null('name').condition('uid',5)# > SELECT * FROM `users`# > WHERE  `name` IS NOT NULL  AND `uid` = %sdb.select('users').condition('name',None)# > SELECT * FROM `users`# > WHERE  `name` IS NULLcomplex conditionsusing db.and_(), db.or_(), we can build complex where conditions:or_cond=db.or_().condition('field1',1).condition('field2','blabla')and_cond=db.and_().condition('field3','what').condition('field4','then?')printdb.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 )exprif you wanna use the aggregate functions like sum, count, please useerpr:fromdbimportexprdb.select('users').fields(expr('count(*)'))# > SELECT count(*) FROM `users`db.select('users').fields(expr('count(uid)','total'))# > SELECT count(uid) AS `total` FROM `users`insertTheinsertapi is used for building insert into sql statement.insert(table, key=’default’):table:the table namekey:the idenfify of databaseq=db.insert('users').values((10,'test_insert'))# > INSERT INTO `users` VALUES(%s, %s)printq._values# > [(10, 'test_insert')]q=db.insert('users').fields('name').values({'name':'insert_1'}).values(('insert_2',))# > INSERT INTO `users` (`name`) VALUES(%s)printq._values# > [('insert_1',), ('insert_2',)]When you useexecuteapi to get result, it will reutrn thelast insert id：printq.execute()# > 2updateTheupdateapi is used for building update sql statement.update(table, key=’default’):table:the table namekey:the idenfify of databasemset and set：mset:the value must be dict tpye, that sets mutil-fileds at once time.set(column, value):set one field one time.the where conditions please seeselectfor more information.db.update('users').mset({'name':None,'uid':12}).condition('name','user_1')# > UPDATE `users` SET `name` = %s, `uid` = %s WHERE  `name` = %sq=(db.update('users').set('name','update_test').set('uid',12).condition('name','user_2').condition('uid',2))# .execute()printq.to_sql()# > UPDATE `users` SET `name` = %s, `uid` = %s WHERE  `name` = %s AND `uid` = %sWhen you useexecuteapi to get result, it will reutrn therowcount：printq.execute()# > 2limitYou can use limit api to lim the quantity of update.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 5deleteThedeleteapi is used for building DELETE FROM sql statement.delete(table, key=’default’):table:the table namekey:the idenfify of databasethe where conditions please seeselectfor more information.db.delete('users').condition('name','user_1')# > DELETE FROM `users` WHERE  `name` = %sWhen you useexecuteapi to get result, it will reutrn therowcount：printq.execute()# > 2to_sql and stryou can use to_sql or __str__ method to the objects ofselect,insert,update,deleteto print the sql you build.q=(db.update('users').set('name','update_test').set('uid',12).condition('name','user_2').condition('uid',2))printq.to_sql()printq# > UPDATE `users` SET `name` = %s, `uid` = %s WHERE  `name` = %s AND `uid` = %stransactiontransaction(table, key=’default’):table:the table namekey:the idenfify of databaseThe simple transaction done all or do nothing, you cann’t set savepoint.# with contextwithdb.transaction()ast:t.delete('users').condition('uid',1).execute()(t.update('users').mset({'name':None,'uid':12}).condition('name','user_1').execute())# the normal wayt=db.transaction()t.begin()t.delete('users').condition('uid',1).execute()(t.update('users').mset({'name':None,'uid':12}).condition('name','user_1').execute())#if failed will rollbackt.commit()Notewhen uses begin must be combine with commit，otherwise the connection will not return connection pool.suggets to usewith contextsimple ormthe orm demosamplesimportmodelfromormimportBackendimportdbdb.setup({'host':'localhost','user':'test','passwd':'test','db':'blog'})user=Backend('user').find_by_username('username')ifuseranduser.check('password'):print'auth'user=model.User('username','email','real_name','password','bio','status','role')ifBackend('user').create(user):print'fine'user=Backend('user').find(12)user.real_name='blablabla....'ifBackend('user').save(user):print'user saved'ifBackend('user').delete(user):print'delete user failed'post=model.Post('title','slug','description','html','css','js','category','status','comments','author')ifnotBackend('post').create(post):print'created failed'FuturePersonal idea:addjoinfor select apiadd a schema class for creating or changing table.add some api for mysql individual sql likereplaceorduplicate updateimprove connection pool.LICENSECopyright (C) 2014-2015 Thomas HuangThis program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 2 of the License.This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.