2016-07-12 14 views
0

Ich schreibe Web-App mit Flask (Python3.4) & psycopg2 Verbindung zu Postgres 9.4 Datenbank.Handle Duplikate Felder in psycopg2

Ich habe Option in meiner Web-App, wo Benutzer ihre eigene Abfrage schreiben und mit Web-App ausführen und Ausgabe in HTML-Tabelle als Antwort erhalten kann.

Ich bin mit Cursor als conn.cursor (cursor_factory = psycopg2.extras.DictCursor) , die ich nicht ändern kann, wie es auch von anderen Teilen des Web-App verwendet wird.

Einer meiner Benutzer schrieb SQL wie unten,

SELECT 
name || ' - ' || address, 
id, 
salary || '; ' || id from company; 

Ausgabe von psycopg2 (Falsch):

?column? id ?column? 
text integer (4) text 
500.55; 1 1 500.55; 1 
500.55; 2 2 500.55; 2 
500.55; 3 3 500.55; 3 
500.55; 4 4 500.55; 4 
999.99; 5 5 999.99; 5 

Hier ist das Ergebnis, das ich habe falsch ist, aufgrund von Doppel key/Feldname ? Spalte? das zweite Vorkommen überschreibt das erste.

Erwartete Ausgabe war:

?column? id ?column? 
text integer (4) text 
AAA - XY 1 500.55; 1 
BBB - ZZ 2 500.55; 2 
ABC - YY 3 500.55; 3 
ABC - CC 4 500.55; 4 
ABC - DD 5 999.99; 5 

Server-Side-Code, die Antwort senden:

# Fetch the column info 
if cur.description is not None: 
    colinfo = [desc for desc in cur.description] 

# Any rows? 
if cur.rowcount > 0: 
    result = [] 
    try: 
     for row in cur: 
     result.append(dict(row)) 
    except psycopg2.ProgrammingError: 
     result = None 

# response for html table 
return Response(
    response=json.dumps(colinfo, result), 
    status=status, 
    mimetype="text/json" 
) 

Bitte legen nahe, Wie kann ich dies mit minimaler Codeänderung beheben?

Inzwischen habe ich auch Problem mit psycopg2 angehoben, https://github.com/psycopg/psycopg2/issues/454

+0

Was ist die Frage? – xeor

+0

@xeor Ich habe die Frage aktualisiert. – n33rma

Antwort

1

Das grundlegende Problem ist, dass Wörterbucheinträge eindeutige Schlüssel haben müssen. Der Spaltenname kann nicht als Schlüssel verwendet werden, wenn mehr als eine Spalte mit demselben Namen vorhanden sein soll. Allerdings könnten Sie für die überprüfen und wenn es einen doppelten Spaltenname ist, machen sie einzigartig irgendwie:

# Fetch the column info 
if cur.description is not None: 
    colinfo = [desc for desc in cur.description] 

# Any rows? 
if cur.rowcount > 0: 
    result = [] 
    rowdict = {} 
    colnames = [desc[0] for desc in cur.description] 

    try: 
     for row in cur: 
     rowdict = {} 
     for x in range(0, len(row)): 

      # make sure column name is unique, if not append index number 
      if colnames[x] in rowdict: 
       rowdict[colnames[x] + "_" + str(x)] = row[x] 
      else: 
       rowdict[colnames[x]] = row[x] 

     result.append(rowdict) 

    except psycopg2.ProgrammingError: 
     result = None 

# response for html table 
return Response(
    response=json.dumps(colinfo, result), 
    status=status, 
    mimetype="text/json" 
) 

Je nachdem, was Sie auf der Client-Seite tun, die Sie haben können haften COLINFO auch zu aktualisieren, zu reflektieren Änderungen an den Spaltennamen, die vorgenommen wurden. Eine weitere Option wäre, eine eindeutige Fehlermeldung zurückzugeben, wenn doppelte Spaltennamen vorhanden sind, so dass der Benutzer die Kontrolle darüber übernehmen kann, welche Spaltennamen er zurückerhält.

Es ist letztlich ein Fehler in psycopg2, aber es gibt nur zurück, was postgres für Spaltennamen in Fällen wie diesem zur Verfügung stellt. Es ist nicht klar, was es stattdessen tun sollte.

Ich gehe davon aus, dass Sie die ernsthaften Risiken der Informationssicherheit in Betracht gezogen und behandelt haben, die mit der Ausführung von SQL von einem Client verbunden sind. Ich versuche nicht, Prediger zu sein, aber es ist ein öffentliches Forum, und ich wäre nachlässig, wenn ich das nicht erwähnen würde, falls jemand anderes so etwas machen möchte.

+0

Danke, aber das ist Arbeit für obige Szenario Aber ich möchte das Problem selbst beheben, da der Benutzer jede Abfrage eingeben kann. Beispiel: 'wählt 1 A, 2, wie B, 3 A, 4 als C;' Hoffnung, das ist meine Frage zu klären :) – n33rma

+0

@ nn33rma Ja, dass es nicht klären. Ich kann dein Problem reproduzieren.So wie ich es verstehe, verwendet DictCursor OrderedDict anstelle des Standard-Dict. Sie können die Spalten weiterhin nach Index referenzieren: row [0], row [1], row [2] usw. Wenn Sie jedoch doppelte Spaltennamen haben, ist die letzte Spalte mit diesem Namen tatsächlich die einzige Spalte, mit der Sie abrufen können dieser Schlüssel. Sie können testen, ob die Länge des Wörterbuchs mit der Anzahl der Schlüssel übereinstimmt. Wenn dies nicht der Fall ist, wissen Sie, dass Sie ein Problem haben, aber es gibt keine Möglichkeit, mehrere Spalten mit demselben Schlüssel abzurufen. – tjs

+0

Ich kann das nicht tun, weil ich Spalte Zuordnung auf der Clientseite habe, bitte verweisen Server-Seite Code, den ich aktualisiert habe, Da dies benutzerabhängigen Code ist kann nicht hart Code :) – n33rma