2010-04-10 34 views
24

新版本的SQLite能夠強制實施外鍵約束,但爲了向後兼容,您必須單獨爲每個數據庫連接打開它!Sqlite/SQLAlchemy:如何執行外鍵?

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,並改變它?

回答

14

我現在有這方面的工作:

下載最新的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添加()事物時,我的導入代碼隱式地處理關係連接,因此永遠不會失敗。在一些ForeignKey()語句中添加'nullable = False'幫助我在這裏。

我測試的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的()的和如果試圖連接無效的fkeys,sqlite現在會正確拋出異常。所以它的作品!如果您刪除偵聽器,則sqlalchemy會愉快地添加無效條目。

我相信主要的問題可能是多個sqlite3.dll的(或.so)左右。

+0

您是否像我所做的那樣使用PRAGMA? – 2010-04-12 23:10:42

+0

謝謝,我也工作。 事實上,問題是我的機器上有多個SQLite副本......修復這個問題,並使用PoolListener完美工作! – 2010-04-21 21:47:29

+0

它的工作原理!但如何使它與poolevent ... – 42n4 2014-09-12 18:02:24

3

我以前有同樣的問題(有外鍵約束的腳本正在經歷,但實際約束沒有被sqlite引擎強制執行);得到它要解決:

  1. 下載,建築,從這裏安裝最新版本的SQLite:sqlite-sqlite-amalgamation;在此之前,我在我的ubuntu機器上安裝了sqlite 3.6.16;目前還不支持外鍵;它應該是3.6.19或更高,讓他們工作。

  2. 從這裏安裝最新版本的pysqlite的:pysqlite-2.6.0

後,我開始變得異常,每當外鍵約束失敗

希望這會有所幫助,至於

+0

我已經有SQLite 3.6.23和pysqlite 2.6.0(和新SQLAlchemy) SQLite文檔說,您必須明確打開FK執行。 根據您的經驗,當它實施時,您是否使用了PRAGMA的東西? – 2010-04-12 23:08:33

+0

是的,我有「PRAGMA foreign_keys = ON;」在我的代碼 – 2010-04-13 01:18:45

2

如果您需要在每個連接上執行一些設置,使用PoolListener

+0

謝謝 - 我試過PoolListener,它確實允許我爲每個數據庫連接執行編譯指示!完善! ...除了該編譯指示仍然不起作用! SQLite引擎仍然不執行外鍵!...我仍然錯過了一個難題。也許這是因爲我在Windows上? SQLite文檔講述了與它構建的「構建選項」有關的內容......但我剛剛獲得了Windows的標準安裝......不確定是否重要? – 2010-04-13 17:57:22

37

對於近期版本(SQLAlchemy的〜0.7)的SQLAlchemy homepage說:

PoolListener已被棄用。請參考PoolEvents

然後由卡爾斯的例子變成:

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) 
+0

conny的答案非常適合新版本的sqlalchemy。用它!主持人應該真的選擇這個是正確的。 – 2013-02-16 12:14:39

3

作爲一個更簡單的方法,如果你的會話創建的背後是一個Python輔助功能集中(而不是直接暴露SQLA引擎),你可以發出「 session.execute('pragma foreign_keys = on')「在返回新創建的會話之前。

如果應用程序的任意部分可能會針對數據庫創建SQLA會話,則只需要使用池偵聽器方法。

+0

簡單而好的答案!這項工作非常適合我 – 2014-04-10 20:54:19

6

SQLite dialect page

SQLite支持外鍵語法發射的CREATE表的語句時,但是默認這些限制對錶的操作沒有影響。

約束下的SQLite檢查有三個先決條件:

  • 至少版本的SQLite 3.6.19必須在使用
  • SQLite的libary必須在不啓用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() 
19

大廈從CONNY和shadowmatter的答案,這裏的代碼,將檢查是否在發佈PRAGMA語句之前使用SQLite3:

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() 
+0

謝謝。這對於那些喜歡'db = SQLAlchemy(app)'方法的人也適用。 – 2016-05-28 20:13:14