2012-08-07 13 views
7

Esto no es realmente un problema, solo quiero entender. Teniendo en cuenta el siguiente código:Comportamiento de eliminación con la relación

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() 

Quiero registros de AB mesa para ser eliminados cuando se eliminan los registros relacionados de B. me trataron 3 tipos de relaciones (marque en el cuadro B):

  • 1: No funciona (AssertionError: Dependencia regla trató de blanco de salida columna de clave principal 'ab.id_b' en la instancia '') , mientras que si intenta eliminarlo directamente en la base de datos, las restricciones se utilizan correctamente y los registros de AB se eliminan.

  • 2: Obras, no lo entiendo por qué esto es necesario porque las bases de datos generadas son idénticos (se puede comprobar el diff en la salida)

  • 3: obras, las limitaciones DB hacer el trabajo.

Dejando (3) de separación, que no entiendo por qué (2) es necesaria, debido a que el ondelete='cascade' ya está establecido, y generó DB es idéntica. Creo que con (1), SQLAlchemy tiene suficiente información para tener el comportamiento correcto.

¿Echo de menos algo? Gracias.

+1

Muchas gracias por esta pregunta. De mucha ayuda. – clime

Respuesta

10

cascade en relationship configura las cascadas de Session operaciones, tales como Session.delete. Es independiente de las directivas ON X CASCADE que pueda tener sobre las restricciones de claves externas en la base de datos.

En su caso, tener cascade='all' dice SQLAlchemy en cascada del Session.delete (entre otras operaciones) del objeto principal (AB) al objeto secundario. Sin él, el modo de operación predeterminado es poner NULL en la columna de clave externa y dejar que el objeto al que se hace referencia sea.

Por otro lado, passive_deletes=True indica a SQLAlchemy que confíe en la base de datos para limpiar los objetos eliminados a través de las directivas ON DELETE CASCADE. Esto evita que SQLAlchemy emita la consulta DELETE por sí mismo, como lo haría en el caso relationship(cascade=...).

+0

Eso es más claro que el documento, gracias :) – tonio

+4

¿Es esta la sección de documentos que lees? http://docs.sqlalchemy.org/en/rel_0_7/orm/session.html#cascades ¿He revisado esa sección docenas de veces durante años, todavía necesito más? Menos ? ¿Qué te desanimó? – zzzeek

Cuestiones relacionadas