2009-07-10 2 views
4

У меня есть куча методов питона, которые следуют этой схеме:ищет более вещий способ доступа к базе данных

def delete_session(guid): 
    conn = get_conn() 
    cur = conn.cursor() 

    cur.execute("delete from sessions where guid=%s", guid) 

    conn.commit() 
    conn.close() 

есть более вещий способ выполнить сырой SQL. 2 строки в начале и конце каждого метода начинают беспокоить меня.

Я не ищу орму, я хочу придерживаться необработанного sql.

ответ

8

Вы можете написать менеджер контекста и использовать оператор with. Например, посмотреть в блоге:

http://jessenoller.com/2009/02/03/get-with-the-program-as-contextmanager-completely-different/

Также документация питон имеет образец, который в значительной степени соответствует вашим потребностям. Смотрите раздел 8.1 на этой странице, в частности, фрагмент кода, который начинается:

db_connection = DatabaseConnection() 
with db_connection as cursor: 
    cursor.execute('insert into ...') 
    cursor.execute('delete from ...') 
    # ... more operations ... 
3

Тщательное о том, что execute, нуждается второй аргумент, чтобы быть [справ] (список только с одним пункт). Что касается вашего вопроса, я обычно просто использую инкапсулирующее соединение и курсор, но похоже, что вы можете использовать контекст выполнения , метод __enter__ дает вам курсор, в то время как совершает или откатывает в зависимости от того, было ли окончание нормальным или путем исключения; это сделало бы код

def delete_session(): 
    with get_cursor() as cur: 
     cur.execute(etc etc) 

Если вам нравится этот стиль, дайте нам знать, и я покажу вам, как писать get_cursor. Другие, несомненно, предложить декоратор вместо этого, так что вы бы написать:

@withcursor 
def delete_session(cur): 
    cur.execute(etc etc) 

, но я думаю, что это делает совершить/откат, среди других вопросов, немного мрачнее. Тем не менее, если это ваше предпочтение, дайте нам знать, и я также смогу показать вам, как написать эту форму.

+0

Он отлично работает с одним только GUID. Есть ли проблема, о которой я не знаю? –

+0

Я думаю, мне нравится подход к контекстному менеджеру. Ссылка, приведенная ars, описывает ее достаточно хорошо, но спасибо за предложение. –

+0

@Ben, второй аргумент cursor.execute должен быть последовательностью значений (обычно кортежей), если вы используете замещение позиционного параметра (например, ваши% s или в других модулях API DB? Или: 1) или отображение (как правило, dict), если вы используете подменю named parameter (например: guid в некоторых модулях API DB) - не знаете, какой модуль DB API вы используете, но это довольно странно, позволяя вам уйти с другими формами, такими как один изолированный , non-mapping, non-mapping 2-й аргумент. –

0

Он не должен быть более вещими, только более структурированным:

def execSql(statement): 
    conn = get_conn() 
    cur = conn.cursor() 
    cur.execute(statement) 
    conn.commit() 
    conn.close() 

def delete_session(guid): 
    execSql("delete from sessions where guid=%s"%(guid)) 
+0

Некоторые из методов, которые я пишу, должны будут взаимодействовать с результатами. Похоже, с этим методом было бы неудобно. Можете ли вы вызвать методы выборки после закрытия соединения? –

+0

Нет, это полезно только для однократных операций. – paxdiablo

0

декоратора?

class SqlExec: 
    def __init__ (self, f): 
     self.f = f 
    def __call__ (self, *args): 
     conn = get_conn() 
     cur = conn.cursor() 
     cur.execute(self.f (*args)) 
     conn.commit() 
     conn.close() 

@SqlExec 
def delete_session(guid): 
     return "delete from sessions where guid=%s" % guid 
3

«У меня есть куча методов питона, которые следуют этому шаблону:»

Это сбивает с толку.

Либо у вас есть куча функций, либо у вас есть куча методов класса.

Букет функций.

Сделайте это вместо этого.

class SQLFunction(object): 
    def __init__(self, connection): 
     self.connection = connection 
    def __call__(self, args=None): 
     self.cursor= self.connection.cursor() 
     self.run(args) 
     self.cursor.commit() 
     self.cursor.close() 

class DeleteSession(SQLFunction): 
    def run(self, args): 
     self.cursor.execute("statement") 

delete_session = DeleteSession(connection) 

Ваши объявления функций являются двумя строками длиннее, но по сути то же самое. Вы можете сделать func1(args), потому что это вызываемый объект.Остальная часть ваша программа должна оставаться неизменной.

Букет методов в одном классе.

class SomeClass(object): 
    def __init__(self, connection): 
     self.connection= connection 
    def sql_execute(self, statement, args= None) 
     self.cursor= self.connection.cursor() 
     self.cursor.execute(statement, args if args is not None else []) 
     self.connection.commit() 
     self.cursor.close() 
    def delete_session(self): 
     self.sql_execute("statement") 

Все ваши методы могут выглядеть delete_session и использовать общий sql_execute метод.

0

Согласно docs, если вы используете SQLite3, вы бы даже не нужноCursor, который, как говорят документы, это «часто лишнее».

Вместо этого вы можете использовать методы быстрого доступа executeexecutemany и executescript непосредственно на объекте подключения:

import sqlite3 

persons = [ 
    ("Hugo", "Boss"), 
    ("Calvin", "Klein") 
    ] 

con = sqlite3.connect(":memory:") 

# Create the table 
con.execute("create table person(firstname, lastname)") 

# Fill the table 
con.executemany("insert into person(firstname, lastname) values (?, ?)", persons) 

# Print the table contents 
for row in con.execute("select firstname, lastname from person"): 
    print row 

print "I just deleted", con.execute("delete from person").rowcount, "rows" 
Смежные вопросы