Новая версия SQLite имеет способность осуществить ограничения Внешнего ключа, но ради назад-совместимости, необходимо включить его для каждого соединения с базой данных отдельно!
sqlite> PRAGMA foreign_keys = ON;
Я использую SQLAlchemy - как я могу удостовериться, что это всегда включается? То, что я попробовал, является этим:
engine = sqlalchemy.create_engine('sqlite:///:memory:', echo=True)
engine.execute('pragma foreign_keys=on')
... но это не работает!... Что я пропускаю?
Править: Я думаю, что моя настоящая проблема состоит в том, что у меня есть больше чем одна версия SQLite, установленного, и Python не использует последний!
>>> import sqlite3
>>> print sqlite3.sqlite_version
3.3.4
Но я просто загрузил 3.6.23 и поместил exe в свой каталог проекта! Как я могу выяснить, какой .exe это использует, и измените его?
Теперь у меня работает следующее:
Скачайте последние сборки 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()])
Затем будьте осторожны, как вы проверяете, работают ли внешние ключи: Здесь у меня возникла некоторая путаница. Когда я использовал sqlalchemy ORM для add()
вещей, мой код импорта неявно обрабатывал подключаемые отношения, поэтому никогда не мог потерпеть неудачу. Добавление 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), лежащих вокруг.
У меня была такая же проблема раньше (скрипты с ограничениями внешних ключей выполнялись, но текущие ограничения не выполнялись движком sqlite); удалось ее решить:
загрузив, построив и установив последнюю версию sqlite отсюда: sqlite-sqlite-amalgamation ; до этого у меня на машине с Ubuntu был sqlite 3.6.16; который еще не поддерживал внешние ключи; он должен быть 3.6.19 или выше, чтобы они работали.
установка последней версии pysqlite отсюда: pysqlite-2.6.0
после этого я начал получать исключения всякий раз, когда ограничение внешнего ключа не удалось
надеюсь, что это поможет, касательно
Если вам нужно выполнить что-то для настройки при каждом подключении, используйте PoolListener .