2016-05-06 3 views
0

Ich habe zwei Tabellen table_a und table_b. table_b.code_b ist der Fremdschlüssel der table_asqlalchemy needload Abfrage kann nicht zum Zählen

table_a 
code_a, val 
----------- 
aaa,100 

table_b 
code_b, name 
------------ 
aaa, name1 

ich mit Verbinden von zwei Tabellen dieses Ergebnis erhalten möchten:

table_result 
code_a,val,name 
--------------- 
aaa,100,name1 

Im Folgenden ist der Python-Code:

class A(db.Model): 
    __tablename__ = 'table_a' 
    code_a = Column(String(20), ForeignKey("table_b.code_b"), primary_key=True) 
    val = Column(Float) 
    b = relationship("B", backref=backref('table_b')) 


class B(db.Model): 
    __tablename__ = 'table_b' 
    code_b = Column(String(20), primary_key=True) 
    name = Column(String(100)) 
    a = relationship("A", backref="table_a") 

where_str = "code_b='aaa'" 
q = A.query.options(joinedload_all(A.b)).filter(text(where_str)) 

rows1 = [i.serialize for i in q.all()] # CORRECT 
rows2 = [i.serialize for i in q.paginate(1,10,False)] # ERROR 

Wenn ich nur alles abfragen, um rows1 zu erhalten, ist es korrektes Ergebnis. Allerdings werde ich Fehler erhalten mit fliessendem rows2: Database: (cx_Oracle.DatabaseError) ORA-00904: "code_b"

ich diesen Fehler debuggen mit Druck die SQL-Anweisung:

SELECT count(*) AS count_1 
FROM (SELECT "table_a".code_a AS "table_a_code_a", 
FROM "table_a" 
WHERE code_b = 'aaa') anon_1 

Es ist klar, dass zwei Tabellen sind NICHT beigetreten.

Wenn aber nur q.all(), wird SQL-Anweisung sein:

SELECT "table_a".code_a AS "table_a_code_a", 
FROM "table_a" LEFT JOIN "table_b" 
WHERE code_b = 'aaa' 

Das ist richtig.

So, wie Sie das richtige Ergebnis beim Erstellen der Seitennummerierung erhalten.


EDIT1:

F: Warum ich where_str verwenden?

A: In der HTML-Seite verwende ich den Abfrage-Generator (http://querybuilder.js.org/), Abfragefilter zu bekommen (vielleicht kompliziert). So ist es bequem, SQLAlchemy Query Filer zu übergeben.

Gibt es bessere Möglichkeiten, dies zu implementieren?


EDIT2: Lösung:

q = A.query.join(A.b).options(contains_eager(A.b)).filter(text(where_str)) 

Antwort

1

Dies ist falsch:

where_str = "code_b='aaa'" 
q = A.query.options(joinedload_all(A.b)).filter(text(where_str)) 

Wie wird SQLAlchemy wissen soll, dass die code_b in Ihrem where_str soll Tabelle entnehmen B?

Versuchen:

q = A.query.join(A.b).filter(B.code_b == "aaa") 

Wenn Sie auch einen joinedload ausführen müssen, dies tun:

q = A.query.join(A.b).options(contains_eager(A.b)).filter(B.code_b == "aaa") 
+0

Dank, sehen Sie bitte meine Frage Update :) – seizetheday

+0

@seizetheday Nur weil Sie das passieren müssen Filter vom Frontend aus bedeutet nicht, dass Sie ein 'text' Konstrukt verwenden müssen. Unabhängig davon, dass Sie ein 'text' Konstrukt verwenden, ist das Problem nicht per se; Das Problem ist, dass Sie 'join' anstelle von' .join' verwenden. – univerio

+0

Danke, Lebensretter! – seizetheday