2011-01-06 11 views
7

Myślałem, że spróbuję uczynić moje połączenie sqlite db funkcją zamiast kopiować/wklejać ~ 6 linii potrzebnych do połączenia i wykonania zapytania w całym miejscu. Chciałbym, aby był uniwersalny, więc mogę użyć tej samej funkcji dla create/select/insert/etc ...Czy mogę umieścić moje połączenie sqlite i kursor w funkcji?

Poniżej jest to, co próbowałem. Zapytania "INSERT" i "CREATE TABLE" działają, ale jeśli wykonuję kwerendę "SELECT", jak mogę pracować z wartościami, które pobiera poza funkcją?
Zazwyczaj chciałbym wydrukować wartości, które pobiera, a także robić z nimi inne rzeczy.

Kiedy zrobić go jak poniżej pojawia się błąd

Traceback (most recent call last): 
File "C:\Users\steini\Desktop\py\database\test3.py", line 15, in <module> 
for row in connection('testdb45.db', "select * from users"): 
ProgrammingError: Cannot operate on a closed database. 

Sądzę więc, że połączenie musi być otwarty, więc można uzyskać wartości z kursorem, ale muszę go zamknąć tak ISN pliku zawsze jest zamknięty.

Oto mój kod badania:

import sqlite3 

def connection (db, arg, cubby): 
    conn = sqlite3.connect(db) 
    conn.execute('pragma foreign_keys = on') 
    cur = conn.cursor() 
    cur.execute(arg) 
    for row in cur: 
     cubby.append(row) 
    conn.commit() 
    conn.close() 

cubby=[] 
connection('testdb.db', "create table users ('user', 'email')", cubby) 
connection('testdb.db', "insert into users ('user', 'email') values ('joey', '[email protected]')", cubby) 
for row in connection('testdb45.db', "select * from users", cubby): 
    print row 

Jak mogę dokonać tej pracy?

EDIT: zmodyfikowany kod trochę więc wartości CUR więc jest dołączany do listy na zewnątrz, ale nadal bardzo złe

Odpowiedz

15

Myślę, że problem jest trochę trudniejsze niż się wydaje na początku.

Błąd jest wyświetlany, ponieważ połączenie z bazą danych zostało zamknięte w funkcji "połączenie".

Prawdopodobnie lepiej skonstruować klasę DatabaseManagement, aby zarządzać pojedynczym połączeniem.

Coś jak:

import sqlite3 

class DatabaseManager(object): 
    def __init__(self, db): 
     self.conn = sqlite3.connect(db) 
     self.conn.execute('pragma foreign_keys = on') 
     self.conn.commit() 
     self.cur = self.conn.cursor() 

    def query(self, arg): 
     self.cur.execute(arg) 
     self.conn.commit() 
     return self.cur 

    def __del__(self): 
     self.conn.close() 

Następnie powinieneś być w stanie zrobić coś takiego:

dbmgr = DatabaseManager("testdb.db") 
for row in dbmgr.query("select * from users"): 
    print row 

to zachowa połączenie otwarte przez cały okres istnienia obiektu.

Nadal może się okazać, że jest to głębszy problem, ale można się bawić i zobaczyć, co działa.

+0

Niesamowita, będę musiała się z tym pogodzić, ale jak na razie ta klasa wydaje się doskonale działać na to, co robię. Dzięki –

+1

Drobne nit, ale potrzebujesz: po instrukcji for w drugim bloku kodu :) –

0

To się nie udaje, ponieważ twoja funkcja zamyka połączenie przed powrotem. Rozwiązaniem tego problemu jest przekształcenie funkcji w generator, który przekazuje wyniki. Coś jak następujący kod nietestowanego powinno działać:

def connection (db, arg): 
    conn = sqlite3.connect(db) 
    conn.execute('pragma foreign_keys = on') 
    cur = conn.cursor() 
    cur.execute(arg) 
    for row in cur: 
     yield row 
    conn.commit() 
    conn.close() 

Trzeba być bardzo ostrożnym, aby spożywać wszystkie wiersze podczas wywoływania tej funkcji, bo jeśli nie, to połączenie nie zostanie zamknięte. Możesz uniknąć tego problemu, patrząc na implementację funkcji niezbędnych do składni with.