2011-12-29 74 views
4

我正在开发对使用sqlalchemy 0.6的现有应用程序的扩展。删除未级联到sqlalchemy中的表

该应用程序创建了非声明式的sqlalchemy表。我试图在我的扩展中创建一个新的表,其中有一个外键列指向应用程序数据库中主表的主键,我正在声明性地创建它。

这一切都正常工作,一旦扩展加载,创建表,并没有投诉。我的表格打印出来并显示新行已添加好。 我想和想的是可能的(但不知道,因为我从来没有使用SQL或任何其他数据库)是我的表中相应的行被删除时,应用程序的主表中的行与相应的外键是删除。

到目前为止,已经尝试了许多排列,没有任何工作。我认为,使用backref集以及使用delete级联定义的关系时,应该没有问题。因为新的表格是在扩展中定义的,所以我不想在主应用程序中编辑代码,至少这是我的目标。但是我遇到的一个问题是,我想要引用的主要应用程序表中没有在其类中定义的成员变量,没有在其映射器中声明其主键,并且只在表中声明了主键。这使得创建关系(ship)子句变得困难,其中的第一个参数必须是类或映射器(在这种情况下,没有声明主键)。 有没有办法实现这个?

ps - 这里是我正在使用的一些代码。 LocalFile是声明类。所有连接细节由主应用程序处理。

if not self.LocalFile.__table__.exists(bind=Engine): 
     self.LocalFile__table__.create(bind=Engine) 

这里是LOCALFILE类 - 基本是一种声明基类与绑定引擎=在构造通过:

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) 

编辑:

后端是sqlite3的。下面是通过使用echo命令创建的表的代码(感谢您指出了这一点,这非常有用 - 我怀疑现有的应用程序生成的sql比必要的要多得多)。 以下报告的sql表创建是删除一行时生成的代码。我个人看不到任何引用本地文件表中可能删除行的语句,但我目前知道的很少。谢谢。

 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 

用于表行产生用于两个表如下:

本地文件表: (中,u” 310 To Yuma') (,u'Ravenous')

在现有的应用程序中的电影表: (,u'IMDb - 3:10至尤马“) (,u'Ravenous”)

代码时删除行这么久,我不能包括它在这里(200行左右 - 删除一行是不是有点太多?),但它没有提及删除localfile表中的一行。有喜欢的语句:

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',) 
+0

能否请您把'回声= TRUE',确保表'local_file'不存在,并运行代码,并检查/张贴表创建生成的'SQL'。另外请提及您正在使用的数据库后端。 – van 2011-12-29 13:00:13

+0

hey van,刚刚完成了 - 编辑主要帖子以包含代码。后端是sqlite3。谢谢! – 2011-12-29 17:22:19

+0

仅供参考:如果您注意到,您会看到每条语句记录两次。这种情况发生在你同时拥有echo = True和明确配置sqlalchemy软件包的日志记录时...... – van 2011-12-29 18:17:05

回答

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) 
+0

非常感谢。这是有效的,我可能从来没有找到自己的答案。在你的脑海中,你是否知道是否有添加PRAGMA延迟的方法,以便在插件初始化时(这将在执行connect语句之后)添加编译指示。谢谢 – 2011-12-29 20:35:26

+0

你可以在初始化你的插件时手动执行它,但这听起来更适用于特定应用程序。 – 2011-12-29 20:42:31

+0

再次感谢,迄今为止,如何将多个附注定义传递给单个执行语句时遇到问题。 (在编译器定义之间是否有分号? - 我的db还没有连接超过一个传递给execute语句的编译指示,语法示例和解释似乎并不存在,我不得不说,对于我认为是如此重要的开发部分,sql的教程和信息似乎有点差,明天我会问一个关于这个问题的专有信息。 – 2011-12-29 23:48:20