SQLAlchemy 中删除未级联到表的情况
2011-12-29 16:29:18,530 INFO sqlalchemy.engine.base.Engine.0x...0650
CREATE TABLE local_file (
_id INTEGER NOT NULL,
_filename VARCHAR(50) NOT NULL,
_filepath VARCHAR(128) NOT NULL,
_movieid INTEGER,
PRIMARY KEY (_id),
FOREIGN KEY(_movieid) REFERENCES movies (movie_id) ON DELETE CASCADE ON UPDATE CASCADE
2011-12-29T16:29:18: I: sqlalchemy.engine.base.Engine.0x...0650(base:1387):
CREATE TABLE local_file (
_id INTEGER NOT NULL,
_filename VARCHAR(50) NOT NULL,
_filepath VARCHAR(128) NOT NULL,
_movieid INTEGER,
PRIMARY KEY (_id),
FOREIGN KEY(_movieid) REFERENCES movies (movie_id) ON DELETE CASCADE ON UPDATE CASCADE
2011-12-29 16:29:18,534 INFO sqlalchemy.engine.base.Engine.0x...0650 ()
2011-12-29T16:29:18: I: sqlalchemy.engine.base.Engine.0x...0650(base:1388): ()
2011-12-29 16:29:18,643 INFO sqlalchemy.engine.base.Engine.0x...0650 COMMIT
2011-12-29T16:29:18: I: sqlalchemy.engine.base.Engine.0x...0650(base:1095): COMMIT
我正在开发一个扩展,目的是为了给一个已经存在的应用添加新功能,这个应用使用的是sqlalchemy 0.6。
这个应用的数据库表是用非声明式的方式创建的。而我想在我的扩展中创建一个新表,这个新表有一个外键列,指向应用数据库中主表的主键。我打算用声明式的方式来创建这个新表。
目前一切都很顺利,扩展加载后新表就创建好了,而且没有任何错误。我能看到新表的内容,并且确认新行已经成功添加。
我希望并认为这是可能的(虽然我不太确定,因为我从来没有用过sql或其他数据库),就是当应用主表中对应外键的行被删除时,我的新表中对应的行也能被删除。
到目前为止,我尝试了很多方法,但都没有成功。我原以为只要设置了反向引用,并且定义了关系为级联删除,就不会有问题。因为新表是在一个扩展中定义的,我不想修改主应用的代码,至少这是我的目标。不过,我面临的一个问题是,我想引用的主应用表在它的类中没有定义成员变量,也没有在映射器中声明主键,只有在表中声明了主键。这让创建关系条款变得困难,因为第一个参数必须是一个类或映射器(而在这种情况下,两者都没有声明主键)。请问有没有办法实现这个呢?
补充说明:我的后端是sqlite3。下面是通过使用echo命令生成的表创建代码(感谢你指出这一点,这非常有用——我已经怀疑现有应用生成的sql比必要的要多得多)。在报告的sql表创建之后,是删除一行时生成的代码。我个人看不出有任何语句提到可能删除本地文件表中的一行,但我目前对sql了解得很少。谢谢。
if not self.LocalFile.__table__.exists(bind=Engine):
self.LocalFile__table__.create(bind=Engine)
这是LocalFile类——Base是一个声明式基类,在构造函数中传入了bind=Engine:
class LocalFile(Base):
__tablename__ = 'local_file'
_id = Column(Integer, Sequence('local_file_sequence', start=1, increment=1), primary_key=True)
_filename = Column(String(50), nullable=False)
_filepath = Column(String(128), nullable=False)
_movieid = Column(Integer, ForeignKey(db.tables.movies.c.movie_id, onupdate='CASCADE', ondelete='CASCADE'))
#movies = relation(db.Movie, backref="local_file", cascade="all")
@property
def filename(self):
return self._filename
@filename.setter
def filename(self, filename):
self._filename = filename
@property
def filepath(self):
return self._filepath
@filepath.setter
def filepath(self, filepath):
self._filepath = filepath
@property
def movieid(self):
return self._movieid
@movieid.setter
def movieid(self, movieid):
self._movieid = movieid
@property
def id(self):
return self._id
@id.setter
def id(self, id):
self._id = id
filename = synonym('_filename', descriptor=filename)
movieid = synonym('_movieid', descriptor=movieid)
filepath = synonym('_filepath', descriptor=filepath)
id = synonym('_id', descriptor=id)
def __init__(self, filename, filepath, movieid):
self._filename = filename
self._filepath = filepath
self._movieid = movieid
def __repr__(self):
return "<User('%s','%s', '%s')>" % (self.filename, self.filepath, self.movieid)
编辑:
删除一行的代码太长了,我无法在这里包含(大约200行——删除一行是不是有点太多了?),但它没有提到删除本地文件表中的一行。有一些语句是:
2011-12-29 17:09:17,141 INFO sqlalchemy.engine.base.Engine.0x...0650 UPDATE movies SET poster_md5=?, updated=? WHERE movies.movie_id = ?
2011-12-29T17:09:17: I: sqlalchemy.engine.base.Engine.0x...0650(base:1387): UPDATE movies SET poster_md5=?, updated=? WHERE movies.movie_id = ?
2011-12-29 17:09:17,142 INFO sqlalchemy.engine.base.Engine.0x...0650 (None, '2011-12-29 17:09:17.141019', 2)
2011-12-29T17:09:17: I: sqlalchemy.engine.base.Engine.0x...0650(base:1388): (None, '2011-12-29 17:09:17.141019', 2)
2011-12-29 17:09:17,150 INFO sqlalchemy.engine.base.Engine.0x...0650 DELETE FROM posters WHERE posters.md5sum = ?
2011-12-29T17:09:17: I: sqlalchemy.engine.base.Engine.0x...0650(base:1387): DELETE FROM posters WHERE posters.md5sum = ?
2011-12-29 17:09:17,157 INFO sqlalchemy.engine.base.Engine.0x...0650 (u'083841e14b8bb9ea166ea4b2b976f03d',)
对于这两个表,使用“for row in table”会产生以下结果:
本地文件表:
(, u' 310 To Yuma')
(, u' Ravenous')
现有应用中的电影表:
(, u'IMDb - 3:10 to Yuma')
(, u'Ravenous')
1 个回答
在SQLite中,你必须明确开启外键支持,否则它会忽略所有与外键相关的SQL语句。
engine = create_engine(database_url)
def on_connect(conn, record):
conn.execute('pragma foreign_keys=ON')
from sqlalchemy import event
event.listen(engine, 'connect', on_connect)