SQLAlchemy 中删除未级联到表的情况

4 投票
1 回答
1600 浏览
提问于 2025-04-17 09:12
     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 个回答

9

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

撰写回答