Sqlite / SQLAlchemy: как применять внешние ключи?

Новая версия SQLite имеет возможность принудительно вводить ограничения внешнего ключа, но для обратной совместимости вам необходимо включить ее для каждого подключения к базе данных отдельно!

sqlite> PRAGMA foreign_keys = ON; 

Я использую SQLAlchemy – как я могу убедиться, что это всегда включается? Я пробовал это:

 engine = sqlalchemy.create_engine('sqlite:///:memory:', echo=True) engine.execute('pragma foreign_keys=on') 

… но это не работает! … Что мне не хватает?

EDIT: Я считаю, что моя реальная проблема заключается в том, что у меня установлена ​​более одной версии SQLite, а Python не использует последнюю версию!

 >>> import sqlite3 >>> print sqlite3.sqlite_version 3.3.4 

Но я только что загрузил 3.6.23 и поместил exe в свой каталог проектов! Как я могу определить, какой именно .exe он использует, и изменить его?

  • Слияние файлов SQLite в один файл db и вопрос «начало / фиксация»
  • Sqlite и Python - вернуть словарь с использованием fetchone ()?
  • Несколько уникальных столбцов в SQLite
  • Переключение с SQLite на MySQL с помощью Flask SQLAlchemy
  • Чтение из удаленных баз данных sqlite3
  • Выполнять команды sqlite3 «dot» из Python или сортировать регистры в утилите командной строки
  • Python / SQLite3: невозможно зафиксировать - транзакция не активна
  • Как проверить, существует ли таблица?
  • 7 Solutions collect form web for “Sqlite / SQLAlchemy: как применять внешние ключи?”

    Теперь у меня это работает:

    Загрузите последние сборки sqlite и pysqlite2, как описано выше: убедитесь, что правильные версии используются во время выполнения python.

     import sqlite3 import pysqlite2 print sqlite3.sqlite_version # should be 3.6.23.1 print pysqlite2.__path__ # eg C:\\Python26\\lib\\site-packages\\pysqlite2 

    Затем добавьте PoolListener:

     from sqlalchemy.interfaces import PoolListener class ForeignKeysListener(PoolListener): def connect(self, dbapi_con, con_record): db_cursor = dbapi_con.execute('pragma foreign_keys=ON') engine = create_engine(database_url, listeners=[ForeignKeysListener()]) 

    Затем будьте осторожны, как вы проверяете, работают ли внешние ключи: у меня была некоторая путаница. При использовании ORM sqlalchemy для добавления () вещей мой код импорта неявно обрабатывал привязки отношений, поэтому никогда не мог потерпеть неудачу. Добавление 'nullable = False' к некоторым выражениям ForeignKey () помогло мне здесь.

    Способ проверки sqlalchemy sqlite для внешнего ключа включен, это сделать ручную вставку из декларативного класса ORM:

     # example ins = Coverage.__table__.insert().values(id = 99, description = 'Wrong', area = 42.0, wall_id = 99, # invalid fkey id type_id = 99) # invalid fkey_id session.execute(ins) 

    Здесь 'wall_id' и 'type_id' являются и ForeignKey (), и sqlite корректно генерирует исключение, если пытается подключить недопустимые fkeys. Так оно и работает! Если вы удалите слушателя, то sqlalchemy с радостью добавит недопустимые записи.

    Я считаю, что основной проблемой может быть несколько sqlite3.dll (или .so), лежащих вокруг.

    Для последних версий (SQLAlchemy ~ 0.7) на главной странице SQLAlchemy говорится:

    PoolListener устарел. Пожалуйста, обратитесь к PoolEvents .

    Тогда пример CarlS становится:

     engine = create_engine(database_url) def _fk_pragma_on_connect(dbapi_con, con_record): dbapi_con.execute('pragma foreign_keys=ON') from sqlalchemy import event event.listen(engine, 'connect', _fk_pragma_on_connect) 

    Основываясь на ответах от conny и shadowmatter, вот код, который будет проверять, используете ли вы SQLite3 перед выпуском инструкции PRAGMA:

     from sqlalchemy import event from sqlalchemy.engine import Engine from sqlite3 import Connection as SQLite3Connection @event.listens_for(Engine, "connect") def _set_sqlite_pragma(dbapi_connection, connection_record): if isinstance(dbapi_connection, SQLite3Connection): cursor = dbapi_connection.cursor() cursor.execute("PRAGMA foreign_keys=ON;") cursor.close() 

    На диалектной странице SQLite :

    SQLite поддерживает синтаксис FOREIGN KEY при испускании операторов CREATE для таблиц, однако по умолчанию эти ограничения не влияют на работу таблицы.

    Проверка ограничений на SQLite имеет три предварительных условия:

    • Должна быть использована хотя бы версия 3.6.19 SQLite
    • Библиотека SQLite должна быть скомпилирована без использования символов SQLITE_OMIT_FOREIGN_KEY или SQLITE_OMIT_TRIGGER.
    • Инструкция PRAGMA foreign_keys = ON должна использоваться во всех соединениях перед использованием.

    SQLAlchemy позволяет автоматически вызывать оператор PRAGMA для новых подключений посредством использования событий:

     from sqlalchemy.engine import Engine from sqlalchemy import event @event.listens_for(Engine, "connect") def set_sqlite_pragma(dbapi_connection, connection_record): cursor = dbapi_connection.cursor() cursor.execute("PRAGMA foreign_keys=ON") cursor.close() 

    Раньше у меня была такая же проблема (скрипты с ограничениями внешних ключей проходили, но принудительные ограничения не выполнялись с помощью механизма sqlite); решил:

    1. загрузка, создание и установка последней версии sqlite отсюда: sqlite-sqlite-amalgamation ; до этого у меня был sqlite 3.6.16 на моей машине ubuntu; которые еще не поддерживали внешние ключи; для работы они должны быть 3.6.19 или выше.

    2. установка последней версии pysqlite отсюда: pysqlite-2.6.0

    после этого я начал получать исключения, когда ограничение внешнего ключа не получилось

    надеюсь, это поможет,

    В качестве более простого подхода, если ваше создание сеанса централизовано за вспомогательной функцией Python (а не непосредственно с помощью механизма SQLA), вы можете просто выдать «session.execute (« pragma foreign_keys = on ») перед возвратом только что созданного сеанса.

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

    Если вам нужно выполнить что-то для настройки в каждом соединении, используйте PoolListener .

    Python - лучший язык программирования в мире.