2012-12-25 6 views
8

Ich habe eine Klasse:SQLAlchemy - Update ForeignKey, wenn die Beziehung Einstellung

class ExampleClass(Base): 
    __tablename__ = 'chart' 
    id = Column(Integer, primary_key=True) 
    element_id = Column(Integer, ForeignKey('anotherTable.id')) 
    element = relationship(AnotherClass) 
    element2_id = Column(Integer, ForeignKey('anotherTable2.id')) 
    element2 = relationship(AnotherClass2) 

Ich möchte einen Lookup tun auf der Grundlage der element_id und element2_id:

class ExampleClass(Base): 
    ... 
    def get_with_element2(self, element2): 
     return session.query(ExampleClass).\ 
         filter_by(element_id = self.element_id, 
           element2_id = element2.id).first() 

Das Problem, das ich finden, dass, wenn Ich instanziiere ein neues ExampleClass Objekt und weise ihm ein element zu, das element_id Feld wird nicht gesetzt:

a = ExampleClass(element=element_obj) 
a.element_id => None 

Wie kann ich das lösen? Was ist der beste Weg, um mit dieser Art von Situation umzugehen?

Antwort

9

Als Erstes gehen alle folgenden Beispiele davon aus, dass Ihre ExampleClass-Instanz mindestens im pending-Zustand ist, wenn nicht im Status "persistent" (dh session.add(a)). Mit anderen Worten: Wenn Sie noch nicht mit einem Session interagieren und das Objekt ExampleClass nicht zu einem Objekt hinzugefügt haben, erhalten Sie kein Verhalten auf Datenbankebene von relationship(), von dem das Beibehalten von Fremdschlüsselspaltenwerten das primäre ist Feature. Sie sind natürlich frei, diese Zuordnung zu machen direkt:

a = ExampleClass(element_id=element_obj.id) 

aber das ist offensichtlich nicht die Nutzung der Automatisierung durch das relationship() Konstrukt zur Verfügung gestellt.

Die Zuordnung der Fremdschlüsselattribute von relationship() während eines flush auftritt, was ein Prozess, der nur dann auftritt, wenn die Interaktion mit der Datenbank erforderlich ist, wie zum Beispiel, bevor Sie eine SQL-Anweisung session.query() emittieren oder bevor Sie die Transaktion abschließen session.commit() mit .

Im Allgemeinen lautet die Philosophie von relationship(), dass Sie hier nur die Attribute "element" und "element2" behandeln und die Fremdschlüsselattribute hinter den Kulissen behandeln. Sie können Ihre Abfrage wie folgt schreiben:

session.query(ExampleClass).\ 
    filter_by(element=self.element).\ 
    filter_by(element2=element2) 

Die ORM wie SomeClass.somerelationship=someobject einen Vergleich nehmen und wandeln die in den Fremdschlüssel Ausdruck SomeClass.some_fk=some_id, aber der Unterschied ist, die Auswertung der endgültige Wert von „some_id“ ist aufgeschoben bis rechts bevor die Abfrage ausgeführt wird. Bevor die Abfrage ausgeführt wird, teilt das Query()-Objekt die Session an "autoflush", was die Auswirkung hat, dass Ihre ExampleClass Zeile zusammen mit der Primärschlüssel-ID element_obj dem Attribut element_id auf dem Objekt ExampleClass zugewiesen wird.

Sie könnte einen ähnlichen Effekt erhalten, während immer noch die FK-Attribute wie diese verwenden, dies meist nur zu verstehen, wie es funktioniert aber:

session.query(ExampleClass).\ 
    filter_by(element_id=bindparam(callable_=lambda: self.element_id)).\ 
    filter_by(element2_id=element2.id) 

oder noch deutlicher, tun die bündig zuerst:

session.flush() 
session.query(ExampleClass).\ 
    filter_by(element_id=self.element_id).\ 
    filter_by(element2_id=element2.id) 

Also in dem Maße, in dem Sie explizit auf Fremdschlüssel-Attribute wie element_id verweisen möchten, müssten Sie auch die Dinge tun, die relationship() explizit für Sie tut.Wenn Sie sich ausschließlich mit Objektinstanzen und dem Attribut relationship() -bound befassen und typische Standardwerte wie autoflush aktiviert lassen, wird im Allgemeinen das "Richtige" ausgeführt und sichergestellt, dass die Attribute bei Bedarf bereit sind.

+0

Vielen Dank für die Erklärung. Ich wusste nicht, ob ich nach der Beziehung selbst filtern konnte und ich wollte die Dinge nicht durcheinander bringen. Also werde ich das definitiv tun. –

Verwandte Themen