2012-08-07 16 views
7

To nie jest problem, po prostu chcę to zrozumieć. Biorąc pod uwagę następujący kod:Usunięcie zachowania w związku

from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy import * 
from sqlalchemy.orm import sessionmaker, relationship 
Base = declarative_base() 

class AB(Base): 
    __tablename__= 'ab' 
    id_a = Column(Integer, ForeignKey('a.id', ondelete='CASCADE'), primary_key=True) 
    id_b = Column(Integer, ForeignKey('b.id', ondelete='CASCADE'), primary_key=True) 
    rel = Column(Unicode) 

class A(Base): 
    __tablename__ = 'a' 
    id = Column(Integer, primary_key=True) 

class B(Base): 
    __tablename__ = 'b' 
    id = Column(Integer, primary_key=True) 
    #1: doesn’t work try to set id_b to null 
    rel_a = relationship('AB') 
    # Works, but cascade='all' seems uneeded to me 
    rel_a = relationship('AB', cascade='all') 
    # Works 
    rel_a = relationship('AB', passive_deletes=True) 

engine = create_engine('sqlite://', echo=True) 

import logging 
logger = logging.getLogger('sqlalchemy.engine.base.Engine') 
logger.setLevel(logging.DEBUG) 
handler = logger.handlers[0] 
handler.setLevel(logging.DEBUG) 
handler.setFormatter(logging.Formatter('%(levelname)s %(message)s', '')) 

Base.metadata.create_all(engine) 

sess = sessionmaker(engine)() 

a1 = A() 
b1 = B() 
ab = AB() 

sess.add_all([a1,b1]) 
sess.flush() 

ab.id_a = a1.id 
ab.id_b = b1.id 
ab.rel = u'truite' 
sess.add(ab) 
sess.flush() 
sess.delete(b1) 
sess.flush() 

chcę zapisy z AB tabeli należy usunąć, gdy powiązane rekordy z B są usuwane. Próbowałem 3 rodzaje stosunków (sprawdź w tabeli B):

  • 1: Nie działa (AssertionError: reguła Zależność próbował pustego out kolumny klucza podstawowego „ab.id_b” na przykład „”) , natomiast jeśli spróbujesz usunąć go bezpośrednio z bazy danych, ograniczenia są poprawnie używane, a rekordy z AB są usuwane.

  • 2: Works, nie rozumiem dlaczego jest to potrzebne, ponieważ wygenerowane bazy danych są identyczne (można sprawdzić diff na wyjściu)

  • 3: prace, ograniczenia DB wykonać pracę.

Pozostawienie (3) od siebie, ja nie rozumiem dlaczego (2) jest potrzebna, ponieważ ondelete='cascade' jest już ustawione, a generowane DB jest identyczna. Zgaduję, że z (1), SQLAlchemy ma wystarczająco dużo informacji, aby mieć prawidłowe zachowanie.

Czy brakuje mi czegoś? Dzięki.

+1

Dziękuję bardzo za to pytanie. Naprawdę pomocny. – clime

Odpowiedz

10

na relationship konfiguruje kaskady operacji Session, takich jak Session.delete. Jest niezależny od wszelkich dyrektyw ON X CASCADE dotyczących ograniczeń kluczy obcych w samej bazie danych.

W twoim przypadku posiadanie cascade='all' mówi SQLAlchemy, aby kaskadowo Session.delete (wśród innych operacji) z obiektu nadrzędnego (AB) do obiektu podrzędnego. Bez niego domyślnym trybem działania jest umieszczenie wartości NULL w kolumnie klucza obcego i pozostawienie obiektu odniesienia.

Z drugiej strony, instruuje SQLAlchemy, aby polegała na bazie danych w celu czyszczenia usuniętych obiektów za pomocą dyrektyw ON DELETE CASCADE. Zapobiega to SQLAlchemy samo wystawieniu zapytania DELETE, tak jak w przypadku relationship(cascade=...).

+0

To jest bardziej wyraźne niż doc, dzięki :) – tonio

+4

jest to sekcja z dokumentami, którą czytasz? http://docs.sqlalchemy.org/en/rel_0_7/orm/session.html#cascades Zrewidowałem tę sekcję dziesiątki razy od lat, nadal potrzebuję więcej? mniej? co cię rzuciło w związku z tym? – zzzeek