2011-12-29 1 views
4

Я разрабатываю расширение для существующего приложения, которое использует sqlalchemy 0.6.delete not cascaded to table in sqlalchemy

Приложение имеет таблицы sqlalchemy, созданные не декларативным способом. Я пытаюсь создать в своем расширении новую таблицу с колонкой внешнего ключа, указывающую на первичный ключ основной таблицы в базе данных приложения, и я создаю ее декларативно.

Все это работает отлично, с таблицей, созданной после загрузки расширения, и без каких-либо претензий. Моя таблица распечатывает и демонстрирует, что новые строки были добавлены в порядке. Я хочу и думаю, что возможно (но не знаю, как я никогда не использовал sql или любую другую базу данных) для того, чтобы соответствующая строка в моей таблице была удалена, когда строка в главной таблице приложения с соответствующим внешним ключом удален.

До сих пор и при многих перестановках, которые были опробованы, ничего не сработало. Я думал, что с настройкой backref и с отношением, определенным с каскадом удаления, не должно быть проблем. Поскольку новая таблица определена в расширении, которое должно быть просто плагином, я не хочу вообще редактировать код в главном приложении, по крайней мере, это моя цель. Одна из проблем, которые у меня есть, состоит в том, что основная таблица приложений, которую я хочу ссылаться, не имеет переменных-членов, определенных в ее классе, не объявляет ее первичный ключ в своем картографе и только имеет первичный ключ, объявленный в таблице , Это затрудняет создание предложения отношения (корабля), первым аргументом которого должен быть класс или картограф (в этом случае ни один из них не объявит первичный ключ). Есть ли способ достичь этого?

ps - вот некоторые из кода, который я использую. LocalFile - это декларативный класс. Все сведения о подключении позаботятся по основному приложению.

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

Вот класс лок_файла - Base декларативный базовый класс с привязкой = 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) 

Edit:

Бэкэнда является sqlite3. Ниже приведен код создания таблицы, созданной с помощью команды echo (спасибо, что указали, что это очень полезно - я уже подозреваю, что существующее приложение генерирует гораздо больше sql, чем это необходимо). После созданной таблицы 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 

для строки в таблице производит следующее для двух таблиц:

локального файла таблицы: (, и»310 To Yuma ') (, u' Ravenous ')

таблица кино в существующем приложении: (, u'IMDb - 3:10 на Юму «) (, u'Ravenous»)

код при удалении строки так долго, что я не могу включить он здесь (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',) 
+0

Не могли бы вы повернуть 'echo = True', убедиться, что таблица' local_file' не существует, и запустите свой код и проверьте/опубликуйте 'SQL', сгенерированную для создания таблицы. Также просьба упомянуть бэкэнд БД, который вы используете. – van

+0

эй ван, только что сделал, что -тобы на главной записи включить код. Бэкэнд - sqlite3. Благодаря! –

+0

только для информации: если вы заметили, вы увидите, что каждый оператор записывается дважды. это происходит, когда у вас есть echo = True, а также настраивает ведение журнала для пакетов sqlalchemy явно ... – van

ответ

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). Спасибо –

+0

Вы можете выполнить его самостоятельно вручную, когда вы инициализируете свой плагин, но это звучит более специфично для приложения. –

+0

Еще раз спасибо, до сих пор были проблемы с установкой того, как передать несколько определений pragma в один оператор execute. (есть ли точка с запятой между определениями прагмы или нет? - мой db еще не подключен с более чем одной прагмой, переданной в оператор execute. Примеры синтаксиса и объяснения для этого, похоже, не существуют. Должен сказать, поскольку я думал, что это важная часть разработки, учебные пособия и информация для sql кажутся немного бедными. Я задам вопрос об этом конкретно завтра. –