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

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

sqlite> PRAGMA foreign_keys = ON; 

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

  • Django: объединение объектов
  •  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 он использует, и изменить его?

  • python sqlalchemy + программа postgresql зависает
  • Как присоединиться к трем таблицам с SQLalchemy и сохранить все столбцы в одной из таблиц?
  • Запрос многих ко многим в SQLAlchemy
  • Использование DATEADD в sqlalchemy
  • Как построить отношения «многие ко многим» с помощью SQLAlchemy: хороший пример
  • Запрос фильтра SQLAlchemy связанным объектом
  • 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 - лучший язык программирования в мире.