2012-12-25 14 views
8

Mam klasy:SQLAlchemy - Aktualizacja ForeignKey przy ustalaniu relacji

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) 

chcę zrobić odnośnika na podstawie element_id i 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() 

Problem Uważam, że jeśli Wywołuję nowy obiekt ExampleClass i przypisuję mu pole element, nie jest ustawione:

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

Jak mogę to rozwiązać? Jaki jest najlepszy sposób radzenia sobie z tego rodzaju sytuacją?

Odpowiedz

9

Po pierwsze, wszystkie poniższe przykłady zakładają, że instancja ExampleClass jest przynajmniej w stanie pending, jeśli nie jest stanem "trwałym" (to jest session.add(a)). Innymi słowy, jeśli jeszcze nie wchodzisz w interakcję z obiektem Session i nie dodano obiektu ExampleClass do jednego, nie uzyskasz żadnego z poziomów bazy danych o wartości relationship(), z których zachowanie wartości kolumny klucza obcego jest podstawowym cecha. Jesteś oczywiście wolny, aby to zadanie bezpośrednio:

a = ExampleClass(element_id=element_obj.id) 

ale to oczywiście nie korzystające z automatyzacji dostarczonych przez relationship() konstruktu.

Przypisanie obcych kluczowych atrybutów przez relationship() występuje podczas flush, która jest procesem, który występuje tylko wtedy, gdy interakcja z bazą danych jest konieczne, tak jak przed emitują instrukcji SQL session.query() lub przed sfinalizować transakcję przy użyciu session.commit() .

Ogólnie filozofią relationship() jest to, że zajmujesz się tu tylko atrybutami "element" i "element2", a atrybuty klucza obcego będą obsługiwane za kulisami. Można napisać zapytanie tak:

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

ORM odbędzie porównanie takiego jak SomeClass.somerelationship=someobject i przekonwertować do klucza obcego wyrazu SomeClass.some_fk=some_id, ale różnica polega na tym, ocenę ostateczną wartość „some_id” jest odroczony, aż do momentu, w którym zapytanie zostanie wykonane. Przed wykonaniem kwerendy obiekt Query() mówi do "automatycznej przepuszczalności", która będzie skutkowała wstawieniem wiersza ExampleClass wraz z głównym identyfikatorem klucza element_obj przypisanym do atrybutu element_id na obiekcie ExampleClass.

można uzyskać podobny efekt, a jednocześnie przy użyciu FK atrybuty tak, to najczęściej tylko zrozumieć, jak to działa, choć:

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

lub nawet bardziej wyraźne, wykonaj równo pierwszy:

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

Jeśli chcesz wyraźnie opisać atrybuty klucza obcego, takie jak element_id, musisz również zrobić to, co wyraźnie zrobisz, relationship().Jeśli zajmujesz się wyłącznie instancjami obiektów i atrybutem danych relationship() i pozostawisz typowe ustawienia domyślne, takie jak autoflush, to zwykle robisz "właściwą rzecz" i upewniasz się, że atrybuty są gotowe w razie potrzeby.

+0

Wielkie dzięki za wyjaśnienie. Nie wiedziałem, czy mogę filtrować przez samą relację i nie chciałem tego zepsuć. Więc na pewno właśnie tak zamierzam to zrobić. –

Powiązane problemy