2013-06-05 3 views
3

Dans mon schéma de la table:bools Stockage dans la base de données SQLite

... disabled BOOLEAN, ... 

Lors de la connexion à db:

db = sqlite3.connect(f, detect_types=sqlite3.PARSE_DECLTYPES) 
sqlite3.register_converter("BOOLEAN", myfunc) 

insérer un disque comme si:

INSERT INTO mytable (disabled, ...) VALUES (:disabled, ...) 

Avec un paramètre dict contenant désactivé: False.

Quand je lis cet enregistrement de retour, myfunc est appelé à convertir le type BOOLEAN:

def myfunc(x): 
    print x, type(x) 

Résultat: 0, <type 'str'> (ce qui bien sûr est évaluée comme vrai quand je veux Faux)

Je veux bools stockées Comme 1 octet INTEGER, je veux simplement les convertir en Python bool en lisant les enregistrements (les autres parties du code attendent les booléens non ints). SQLite les stocke-t-il sous forme de chaînes ou les convertit-il en chaînes avant d'appeler myfunc? Pourquoi?

P.S. - J'ai essayé d'utiliser sqlite3.register_adapter(bool, int), en vain.

+0

Je ne sais pas pourquoi vous obtenez de nouveau une chaîne, mais les convertir en et ensuite bool devrait être une solution de contournement pour l'instant. – pypat

Répondre

12

Vous voulez utiliser une combinaison de register_adapter et register_converter pour les deux directions:

sqlite3.register_adapter(bool, int) 
sqlite3.register_converter("BOOLEAN", lambda v: bool(int(v))) 

SQLite utilise un dynamic type system mais pour les types de mesure, il n'a aucun moyen de savoir avec certitude si 0 est une chaîne ou un nombre entier, de sorte que vous obtenez une chaîne ici.

Sinon, utilisez:

sqlite3.register_converter("BOOLEAN", lambda v: v != '0') 

ce qui est beaucoup plus souple et robuste en matière de données existantes, mais vous peut-être veulent une exception à soulever.

Démo:

>>> import sqlite3 
>>> db = sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_DECLTYPES) 
>>> sqlite3.register_adapter(bool, int) 
>>> sqlite3.register_converter("BOOLEAN", lambda v: bool(int(v))) 
>>> db.execute('CREATE TABLE foo (bar BOOLEAN)') 
<sqlite3.Cursor object at 0x10a17a340> 
>>> db.execute('INSERT INTO foo VALUES (?)', (True,)) 
<sqlite3.Cursor object at 0x10a17a3b0> 
>>> db.execute('INSERT INTO foo VALUES (?)', (False,)) 
<sqlite3.Cursor object at 0x10a17a340> 
>>> for row in db.execute('SELECT * FROM foo'): 
...  print row 
... 
(True,) 
(False,) 
+0

Cela ne fonctionne pas dans mon application. Le convertisseur, bool, est donné une chaîne "0" qui évalue à True au lieu de False. –

+0

@peuping: avez-vous vu ma mise à jour et ma démo? Je vous montre dans la réponse que cela fonctionne. :-) –

2

sqlite3 n'a pas un type boolean - il suffit de stocker votre champ comme integer à la place:

>>> import sqlite3 
>>> db = sqlite3.connect(':memory:') 
>>> db.execute('create table test (col1 integer)') 
<sqlite3.Cursor object at 0x3737880> 
>>> db.execute('insert into test values (?)', (1,)) 
<sqlite3.Cursor object at 0x3737960> 
>>> print list(db.execute('select * from test')) 
[(1,)] 

Un type de convertisseur de mesure prend la forme de chaîne d'une colonne stockée, puis vous êtes censé utiliser que pour créer un nouveau type de celui-ci ...

Si vous avez fait quelque chose comme:

db = sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_DECLTYPES) 
def myfunc(col): 
    val = int(col) == 1 
    print val, type(val) 
    return val 

sqlite3.register_converter('boolean', myfunc) 

db.execute('create table blah (something boolean)') 
db.executemany('insert into blah values (?)', [(True,), (False,)]) 
list(db.execute('select * from blah')) 

Yo u'll obtenir un bool retourné, ce qui est ce que je pense que vous voulez - cependant, vous devrez vous assurer de gérer les exceptions, sinon ils sont silencieusement supprimés ...

+0

C'est ce que le PO essaie de résoudre; vous pouvez adapter les types. –

+0

Je sais que je peux convertir la chaîne en nombre entier. Ma question est pourquoi il me donne une chaîne au lieu d'un entier pour commencer. –

Questions connexes