2016-05-24 7 views
3

Ich bin neu in Cursor und ich versuche, durch den Aufbau einer dynamischen Python SQL-Anweisung INSERT mit einem hygienisiert Methode für sqlite3 zu üben:Wie übergibt man Spaltennamen sauber in den Cursor, Python/SQLite?

import sqlite3 
conn = sqlite3.connect("db.sqlite") 
cursor = conn.cursor() 
list = ['column1', 'column2', 'column3', 'value1', 'value2', 'value3'] 
cursor.execute("""insert into table_name (?,?,?) 
values (?,?,?)""", list) 

Wenn ich dies zu nutzen versuchen, bekomme ich einen Syntaxfehler " sqlite3.OperationalError: nahe "?" "auf der Linie mit den Werten. Dies ist trotz der Tatsache, dass, wenn ich die Spalten hart Code (und entfernen Sie die Spaltennamen aus der Liste), habe ich kein Problem. Ich könnte mit% s konstruieren, aber ich weiß, dass die sanierte Methode bevorzugt wird.

Wie lege ich diese sauber ein? Oder fehlt mir etwas Offensichtliches?

Antwort

3

Die (?,?,?) Syntax nur für die Tupel, die Werte enthält, imho funktioniert ... Das wäre

der Grund für sqlite3.OperationalError sein Ich glaube (!), Dass Sie sollten bauen es ähnlich wie:

cursor.execute("INSERT INTO {tn} ({f1}, {f2}) VALUES (?, ?)".format(tn='testable', f1='foo', f1='bar'), ('test', 'test2',)) 

Aber das ist nicht das Injektions Problem nicht lösen, wenn der Benutzer Tabellennamen zu schaffen erlaubt ist oder Flurname selbst aber.

Ich kenne keine eingebaute Methode, um dagegen zu helfen. Aber man könnte eine Funktion wie das verwenden:

def clean(some_string): 
    return ''.join(char for char in some_string if char.isalnum()) 

den usergiven Tabellennamen oder Feldnamen zu sanieren. Dies sollte ausreichen, da Tabellen-/Feldnamen in der Regel nur aus alphanumerischen Zeichen bestehen.

Vielleicht kann es klug sein, um zu überprüfen, ob

some_string == clean(some_string) 

Und wenn Falsch, eine schöne Ausnahme auf der sicheren Seite zu sein, fällt.

Während meiner Arbeit mit sql & Python fühlte ich, dass Sie den Benutzer nicht seine Tabellen und Feldnamen selbst nennen lassen müssen. So ist/war es für mich selten nötig.

Wenn jemand mehr ausarbeiten und seine Einsichten geben könnte, würde ich es sehr schätzen. So

+0

Ich schätze die Einsicht - ich kann verstehen, dass ich die Feldnamen nicht bereinigen muss (ich plane, sie dynamisch durch eine andere interne Klassenmethode in derselben Klasse zu erzeugen), ich habe einfach versucht, die beiden Feldnamen einzufügen und die Werte. Ich denke jetzt (nachdem ich Ihre Antwort gelesen habe), die Methode% s zu verwenden, um die anfängliche Zeichenfolge zu generieren, die die Zeichenfolge? Und dann füge einfach die ganze Saite ein ... Ich melde mich bei dir, ob das funktioniert hat. – whybull

+0

In der Tat. Wenn ich für mich selbst code, bin ich eher faul und mache so etwas: '" SELECT * FROM hashtable WHERE% s = ?; "' – krysopath

2

Erstens würde ich durch die Schaffung einer Zuordnung von Spalten und Werte beginnen:

data = {'column1': 'value1', 'column2': 'value2', 'column3': 'value3'} 

Und bekommen, dann sind die Spalten von hier:

columns = data.keys() 
# ['column1', 'column3', 'column2'] 

Nun müssen wir Platzhalter für beide erstellen Spalten und für Werte:

placeholder_columns = ", ".join(data.keys()) 
# 'column1, column3, column2' 

placeholder_values = ", ".join([":{0}".format(col) for col in columns]) 
# ':column1, :column3, :column2' 
Dann

schaffen wir die INSERT SQL-Anweisung:

sql = "INSERT INTO table_name ({placeholder_columns}) VALUES ({placeholder_values})".format(
    placeholder_columns=placeholder_columns, 
    placeholder_values=placeholder_values 
) 

# 'INSERT INTO table_name (column1, column3, column2) VALUES (:column1, :column3, :column2)' 

Nun, was wir in sql haben, ist eine gültige SQL-Anweisung mit benannten Parametern. Jetzt können Sie diese SQL-Abfrage mit den Daten ausführen:

cursor.execute(sql, data) 

Und da data Schlüssel und Werte hat, werden die benannten Platzhalter in der Abfrage verwenden, um die Werte in der richtigen Spalten einzufügen.

Werfen Sie einen Blick auf die documentation, um zu sehen, wie benannte Parameter verwendet werden. Von dem was ich sehe, muss man sich nur um die Bereinigung der einzufügenden Werte kümmern. Und es gibt zwei Möglichkeiten, dies zu tun: 1) entweder mit einem Fragezeichenstil oder 2) benanntem Parameterstil.

+0

Lustige ist, dass ich mit einem Dictionary-Objekt gestartet und Dann habe ich es auf eine Schlüsselliste und eine Werteliste aufgeteilt und dann einfach verkettet, um meine Liste zu erhalten. Meine einzige Sorge ist wirklich der Verlust der sanitären Einrichtungen, dass die? Methodengewinne. Wie ich bereits erwähnt habe, könnte ich die Insert-Zeichenfolge mit einer ähnlichen Methode erstellen, aber ich sehe nicht, wie Ihre Methode die Daten bereinigen würde. – whybull

+0

@ user2833273: Ich habe meine Antwort aktualisiert, so dass sie benannte Parameter verwendet, die eine Bereinigung der Werte sicherstellen. Ich habe auch den Link zu der Dokumentation für das gleiche hinzugefügt. Was die Bereinigung des Spaltennamens betrifft, wird dies weder durch ein Fragezeichen noch durch benannte Parameter unterstützt. Sie werden nur für Werte verwendet. – AKS

0
import sqlite3 
    conn = sqlite3.connect("db.sqlite") 
    cursor = conn.cursor() 
## break your list into two, one for column and one for value 
    list = ['column1', 'column2', 'column3'] 
    list2= ['value1', 'value2', 'value3'] 
    cursor.execute("""insert into table_name("""+list[0]+""","""+list[1]+""","""+list[2]+""") 
    values ("""+list2[0]+""","""+list2[1]+""","""+list2[2]+""")""") 
+0

https://xkcd.com/327/ – whybull

1

, hier ist was ich Umsetzung endete, dachte ich, es ist ziemlich pythonic war, aber nicht ohne Krysopath Einsicht beantwortet haben könnte:

columns = ['column1', 'column2', 'column3'] 
    values = ['value1', 'value2', 'value3'] 
    columns = ', '.join(columns) 
    insertString=("insert into table_name (%s) values (?,?,?,?)" %columns) 
    cursor.execute(insertString, values) 
+0

braucht ein bisschen mehr ' str.format() '+ snake_case und ein bisschen weniger% -formatierend + camelCase, bevor es pythonisch ist;) ... löst auch nicht das Injection-Problem, ofc (was es merkwürdig macht, dass du den Bobby Tables Comic verlinkt hast) auf der anderen Antwort), aber das ist in Ordnung, wenn Sie die Kontrolle über alle möglichen Eingaben haben. –

+0

Danke für den Downvote, als relativ neuer Nutzer schätze ich die Unterstützung der Community sehr. Gehäuse beiseite, es löst tatsächlich das Injektionsproblem. Selbst wenn die Funktion aufgerufen wurde, weil sie das "?" Syntax in der Insert-Anweisung wird es nicht wirklich ausführbare sql. Aber nochmal, danke für den Downvote. – whybull