удалить не каскадно в таблицу в sqlalchemy

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

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

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

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

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

    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)

Редактировать:

Бэкенд — 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

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

локальная файловая таблица: (, 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',)

person miller the gorilla    schedule 29.12.2011    source источник
comment
Не могли бы вы включить echo=True, убедиться, что таблица local_file не существует, запустить свой код и проверить/опубликовать SQL, сгенерированный для создания таблицы. Также, пожалуйста, укажите серверную часть БД, которую вы используете.   -  person van    schedule 29.12.2011
comment
эй, Ван, только что сделал это - отредактировал основной пост, чтобы включить код. Бэкенд — sqlite3. Спасибо!   -  person miller the gorilla    schedule 29.12.2011
comment
просто для информации: если вы заметили, вы видите, что каждый оператор регистрируется дважды. это происходит, когда у вас есть echo = True, а также явно настроено ведение журнала для пакетов sqlalchemy...   -  person van    schedule 29.12.2011


Ответы (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)
person Michael Merickel    schedule 29.12.2011
comment
Большое спасибо. Это сработало, и я, вероятно, никогда не нашел бы ответ самостоятельно. Из верхней части вашей головы вы знаете, есть ли способ добавить отложенную PRAGMA, чтобы я мог добавить прагму при инициализации плагина (что произойдет после выполнения оператора подключения). Спасибо - person miller the gorilla; 30.12.2011
comment
Вы можете выполнить его самостоятельно вручную при инициализации плагина, но это звучит более специфично для приложения. - person Michael Merickel; 30.12.2011
comment
Еще раз спасибо, до сих пор были проблемы с установлением того, как передать несколько определений прагмы в один оператор выполнения. (есть ли точка с запятой между определениями прагмы или нет? - моя БД еще не связана с более чем одной прагмой, переданной в оператор выполнения. Примеры синтаксиса и объяснения этого, похоже, не существуют. Я должен сказать, для того, что я считал такой важной частью разработки, учебники и информация по sql кажутся немного скудными.Я задам вопрос конкретно об этом завтра. - person miller the gorilla; 30.12.2011
comment
Ага - теперь я понял - я могу вызвать connection.execute в любое время с оператором прагмы любого рода, и пока sqlite скомпилирован с этой опцией, я смеюсь. ХеХе. Все сделано. :-) - person miller the gorilla; 30.12.2011