資料庫¶
Django 官方支援以下資料庫
還有一些由協力廠商提供的資料庫後端。
Django 試圖在所有資料庫後端上支援盡可能多的功能。但是,並非所有資料庫後端都相同,我們必須針對要支援哪些功能以及可以安全地做出哪些假設做出設計決策。
此檔案描述了一些可能與 Django 使用相關的功能。它並非旨在取代伺服器特定的文件或參考手冊。
一般注意事項¶
持續連線¶
持續連線可以避免在每個 HTTP 請求中重新建立資料庫連線的開銷。它們由 CONN_MAX_AGE
參數控制,該參數定義連線的最大存活時間。它可以針對每個資料庫獨立設定。
預設值為 0
,保留在每個請求結束時關閉資料庫連線的歷史行為。若要啟用持續連線,請將 CONN_MAX_AGE
設定為正整數(以秒為單位)。對於無限持續連線,請將其設定為 None
。
連線管理¶
Django 在首次進行資料庫查詢時開啟資料庫連線。它會保持此連線開啟,並在後續請求中重複使用。Django 會在超過 CONN_MAX_AGE
定義的最大存活時間或無法再使用時關閉連線。
詳細來說,Django 會在需要時自動開啟資料庫連線,且沒有現有連線時 — 要嘛是因為這是第一個連線,要嘛是因為先前的連線已關閉。
在每個請求開始時,如果連線已達到最大存活時間,Django 會關閉該連線。如果您的資料庫在一段時間後終止閒置連線,您應該將 CONN_MAX_AGE
設定為較低的值,這樣 Django 才不會嘗試使用已被資料庫伺服器終止的連線。(這個問題可能只會影響流量非常低的網站。)
在每個請求結束時,如果連線已達到最大存活時間或處於無法復原的錯誤狀態,Django 會關閉該連線。如果在處理請求時發生任何資料庫錯誤,Django 會檢查連線是否仍可運作,如果無法運作則會關閉連線。因此,資料庫錯誤最多影響每個應用程式工作執行緒的每個請求;如果連線變得無法使用,則下一個請求會取得新的連線。
將 CONN_HEALTH_CHECKS
設定為 True
可用於提高連線重複使用的穩健性,並防止在連線已被資料庫伺服器關閉,現在準備接受並服務新連線時發生錯誤,例如在資料庫伺服器重新啟動後。健康檢查僅在每個請求中執行一次,且僅在處理請求期間存取資料庫時執行。
注意事項¶
由於每個執行緒都維護自己的連線,因此您的資料庫必須至少支援與您的工作執行緒一樣多的同時連線。
有時,大多數的視圖不會存取資料庫,例如因為它是外部系統的資料庫,或是因為快取。在這種情況下,您應該將 CONN_MAX_AGE
設定為低值,甚至 0
,因為維護不太可能重複使用的連線是沒有意義的。這將有助於將此資料庫的同時連線數保持在較小的值。
開發伺服器會為處理的每個請求建立一個新的執行緒,從而抵消了持續連線的效果。請勿在開發期間啟用它們。
當 Django 建立與資料庫的連線時,它會根據所使用的後端設定適當的參數。如果啟用持續連線,則此設定不會在每個請求重複執行。如果您修改了連線的隔離層級或時區等參數,您應該在每個請求結束時還原 Django 的預設值,在每個請求開始時強制設定適當的值,或停用持續連線。
如果在長期執行的程序中建立連線,在 Django 的請求-回應週期之外,連線將保持開啟狀態,直到明確關閉或發生逾時。您可以使用 django.db.close_old_connections()
關閉所有舊的或無法使用的連線。
編碼¶
Django 假設所有資料庫都使用 UTF-8 編碼。使用其他編碼可能會導致意外行為,例如資料庫因 Django 中有效的資料而產生「值太長」的錯誤。請參閱以下特定於資料庫的注意事項,以了解如何正確設定資料庫。
PostgreSQL 注意事項¶
Django 支援 PostgreSQL 13 及更高版本。需要 psycopg 3.1.8+ 或 psycopg2 2.8.4+,但建議使用最新的 psycopg 3.1.8+。
注意
對 psycopg2
的支援可能會在未來某個時間點被棄用並移除。
PostgreSQL 連線設定¶
請參閱 HOST
以取得詳細資料。
若要使用來自 連線服務檔案的服務名稱和來自 密碼檔案的密碼進行連線,您必須在 DATABASES
中的資料庫組態的 OPTIONS
部分中指定它們
settings.py
¶DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"OPTIONS": {
"service": "my_service",
"passfile": ".my_pgpass",
},
}
}
.pg_service.conf
¶[my_service]
host=localhost
user=USER
dbname=NAME
port=5432
.my_pgpass
¶localhost:5432:NAME:USER:PASSWORD
PostgreSQL 後端將 OPTIONS
的內容作為關鍵字引數傳遞給連線建構函式,從而可以更進階地控制驅動程式行為。所有可用的參數都已在 PostgreSQL 文件中詳細說明。
警告
不支援將服務名稱用於測試目的。這可能會在稍後實作。
最佳化 PostgreSQL 的組態¶
Django 需要以下參數才能連線資料庫
client_encoding
:'UTF8'
,default_transaction_isolation
: 預設為'read committed'
,或是在連線選項中設定的值(請參閱下方),
如果這些參數已具有正確的值,Django 不會為每個新連線設定它們,這會稍微提高效能。您可以直接在 postgresql.conf
中設定它們,或更方便地使用 ALTER ROLE 來為每個資料庫使用者設定它們。
Django 在沒有這種最佳化的情況下也可以正常運作,但每個新連線都會執行一些額外的查詢來設定這些參數。
隔離層級¶
如同 PostgreSQL 本身,Django 預設使用 READ COMMITTED
隔離等級。如果您需要更高的隔離等級,例如 REPEATABLE READ
或 SERIALIZABLE
,請在您的資料庫設定的 OPTIONS
部分中設定,該設定位於 DATABASES
中。
from django.db.backends.postgresql.psycopg_any import IsolationLevel
DATABASES = {
# ...
"OPTIONS": {
"isolation_level": IsolationLevel.SERIALIZABLE,
},
}
注意
在較高的隔離等級下,您的應用程式應該準備好處理序列化失敗時引發的例外。此選項是為進階用途設計的。
角色¶
如果您需要對資料庫連線使用與建立連線時不同的角色,請在您的資料庫設定的 OPTIONS
部分中設定,該設定位於 DATABASES
中。
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
# ...
"OPTIONS": {
"assume_role": "my_application_role",
},
},
}
連線池¶
若要將連線池與 psycopg 搭配使用,您可以在 OPTIONS
部分中設定 "pool"
,該設定位於您的資料庫設定的 DATABASES
中,並將其設定為要傳遞至 ConnectionPool
的字典,或者設定為 True
以使用 ConnectionPool
的預設值。
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
# ...
"OPTIONS": {
"pool": True,
},
},
}
此選項需要安裝 psycopg[pool]
或 psycopg-pool,並且會在使用 psycopg2
時被忽略。
伺服器端參數綁定¶
對於 psycopg 3.1.8+,Django 預設使用 客戶端綁定游標。如果您想要使用 伺服器端綁定,請在您的資料庫設定的 OPTIONS
部分中設定,該設定位於 DATABASES
中。
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
# ...
"OPTIONS": {
"server_side_binding": True,
},
},
}
此選項在使用 psycopg2
時會被忽略。
針對 varchar
和 text
欄位的索引¶
當在您的模型欄位上指定 db_index=True
時,Django 通常會輸出單一的 CREATE INDEX
陳述式。但是,如果該欄位的資料庫類型為 varchar
或 text
(例如,由 CharField
、FileField
和 TextField
使用),那麼 Django 將會建立額外的索引,該索引會針對該欄使用適當的 PostgreSQL 運算子類別。額外的索引對於正確執行使用 SQL 中的 LIKE
運算子的查詢是必要的,這就像是 contains
和 startswith
查詢類型一樣。
新增擴充功能的遷移操作¶
如果您需要使用遷移來新增 PostgreSQL 擴充功能(例如 hstore
、postgis
等),請使用 CreateExtension
操作。
伺服器端游標¶
當使用 QuerySet.iterator()
時,Django 會開啟一個 伺服器端游標。預設情況下,PostgreSQL 假設只會提取游標查詢結果的前 10%。查詢規劃器會花費較少的時間來規劃查詢,並更快開始返回結果,但如果檢索的結果超過 10%,這可能會降低效能。PostgreSQL 對於游標查詢檢索的列數的假設是透過 cursor_tuple_fraction 選項來控制的。
交易池和伺服器端游標¶
在交易池模式下使用連線池程式(例如 PgBouncer)需要停用該連線的伺服器端游標。
伺服器端游標是連線本地的,並且當 AUTOCOMMIT
為 True
時,會在交易結束時保持開啟狀態。後續交易可能會嘗試從伺服器端游標提取更多結果。在交易池模式下,無法保證後續交易會使用相同的連線。如果使用了不同的連線,則當交易參考伺服器端游標時會引發錯誤,因為伺服器端游標只能在它們建立的連線中存取。
一種解決方案是在 DATABASES
中設定 DISABLE_SERVER_SIDE_CURSORS
為 True
,以停用連線的伺服器端游標。
為了在交易池模式下受益於伺服器端游標,您可以設定另一個資料庫連線,以執行使用伺服器端游標的查詢。此連線需要直接連接到資料庫,或連接到工作階段池模式中的連線池程式。
另一種選擇是使用 atomic()
區塊來包裝每個使用伺服器端游標的 QuerySet
,因為它會在交易期間停用 autocommit
。這樣一來,伺服器端游標只會在交易期間存續。
手動指定自動遞增主索引鍵的值¶
Django 使用 PostgreSQL 的身分欄來儲存自動遞增主索引鍵。身分欄會使用 序列 的值來填入,該序列會追蹤下一個可用的值。手動將值指派給自動遞增欄位不會更新該欄位的序列,這可能會在稍後導致衝突。例如
>>> from django.contrib.auth.models import User
>>> User.objects.create(username="alice", pk=1)
<User: alice>
>>> # The sequence hasn't been updated; its next value is 1.
>>> User.objects.create(username="bob")
IntegrityError: duplicate key value violates unique constraint
"auth_user_pkey" DETAIL: Key (id)=(1) already exists.
如果您需要指定此類值,請在之後重設序列,以避免重複使用表格中已有的值。sqlsequencereset
管理命令會產生執行此操作的 SQL 陳述式。
測試資料庫範本¶
您可以使用 TEST['TEMPLATE']
設定來指定 範本(例如 'template0'
),以從中建立測試資料庫。
透過非持久設定來加速測試執行¶
您可以透過設定 PostgreSQL 為非持久性來加速測試執行時間。
警告
這很危險:在伺服器當機或電源中斷的情況下,這會使您的資料庫更容易遺失資料或損毀。僅在您可以輕鬆還原叢集中所有資料庫的全部內容的開發機器上使用此設定。
MariaDB 註記¶
Django 支援 MariaDB 10.5 及更高版本。
若要使用 MariaDB,請使用 MySQL 後端,兩者共用此後端。如需更多詳細資訊,請參閱 MySQL 註記。
MySQL 註記¶
版本支援¶
Django 支援 MySQL 8.0.11 及更高版本。
Django 的 inspectdb
功能會使用 information_schema
資料庫,其中包含所有資料庫綱要的詳細資料。
Django 預期資料庫支援 Unicode (UTF-8 編碼),並將強制執行交易和參考完整性的任務委派給資料庫。 重要的是要注意,當使用 MyISAM 儲存引擎時,後兩者實際上不會由 MySQL 強制執行,請參閱下一節。
儲存引擎¶
MySQL 有幾個儲存引擎。 您可以在伺服器設定中變更預設的儲存引擎。
MySQL 的預設儲存引擎是InnoDB。 這個引擎完全支援交易,並支援外鍵參照。 這是建議的選擇。 然而,InnoDB 的自動遞增計數器會在 MySQL 重新啟動時遺失,因為它不會記住 AUTO_INCREMENT
值,而是將其重新建立為「max(id)+1」。 這可能會導致不慎重複使用 AutoField
值。
MyISAM 的主要缺點是不支援交易或強制執行外鍵約束。
MySQL DB API 驅動程式¶
MySQL 有幾個驅動程式實作了 PEP 249 中描述的 Python 資料庫 API。
mysqlclient 是一個原生驅動程式。 它是建議的選擇。
MySQL Connector/Python 是 Oracle 提供的純 Python 驅動程式,不需要 MySQL 用戶端程式庫或標準程式庫以外的任何 Python 模組。
這些驅動程式是執行緒安全的,並提供連線池。
除了 DB API 驅動程式之外,Django 還需要一個配接器才能從其 ORM 存取資料庫驅動程式。 Django 為 mysqlclient 提供了一個配接器,而 MySQL Connector/Python 則包含自己的配接器。
mysqlclient¶
Django 需要 mysqlclient 1.4.3 或更新版本。
MySQL Connector/Python¶
MySQL Connector/Python 可從下載頁面取得。 Django 配接器可在 1.1.X 及更新版本中使用。 它可能不支援最新版本的 Django。
時區定義¶
如果您計劃使用 Django 的時區支援,請使用 mysql_tzinfo_to_sql 將時區表載入 MySQL 資料庫。 這只需要針對您的 MySQL 伺服器執行一次,而不是每個資料庫執行一次。
建立資料庫¶
您可以使用命令列工具和以下 SQL 建立您的資料庫
CREATE DATABASE <dbname> CHARACTER SET utf8;
這確保所有表格和欄位預設都會使用 UTF-8。
排序設定¶
欄位的排序設定控制資料的排序順序,以及哪些字串比較為相等。 您可以指定 db_collation
參數來設定 CharField
和 TextField
的欄位排序名稱。
排序也可以在資料庫範圍層級和每個表格上設定。 這在 MySQL 文件中有詳細的說明。 在這種情況下,您必須直接操作資料庫設定或表格來設定排序。 Django 沒有提供 API 來變更它們。
預設情況下,使用 UTF-8 資料庫時,MySQL 會使用 utf8_general_ci
排序。 這會導致所有字串相等比較都以不區分大小寫的方式完成。 也就是說,"Fred"
和 "freD"
在資料庫層級被視為相等。 如果您在欄位上有唯一約束,則嘗試將 "aa"
和 "AA"
都插入同一個欄位中是不合法的,因為它們使用預設排序比較時會被視為相等 (因此不唯一)。 如果您想要在特定欄位或表格上進行區分大小寫的比較,請變更欄位或表格以使用 utf8_bin
排序。
請注意,根據MySQL Unicode 字元集,utf8_general_ci
排序的比較速度比 utf8_unicode_ci
的比較速度快,但稍微不正確。 如果您的應用程式可以接受此行為,您應該使用 utf8_general_ci
,因為它速度更快。 如果這不可接受 (例如,如果您需要德語字典順序),請使用 utf8_unicode_ci
,因為它更準確。
警告
模型表單集會以區分大小寫的方式驗證唯一欄位。 因此,當使用不區分大小寫的排序時,具有僅大小寫不同的唯一欄位值的表單集會通過驗證,但在呼叫 save()
時,會引發 IntegrityError
。
連線到資料庫¶
請參閱設定文件。
連線設定會依此順序使用
換句話說,如果您在 OPTIONS
中設定資料庫的名稱,這將優先於 NAME
,而 NAME
將覆蓋 MySQL 選項檔案中的任何內容。
以下是一個使用 MySQL 選項檔案的範例設定
# settings.py
DATABASES = {
"default": {
"ENGINE": "django.db.backends.mysql",
"OPTIONS": {
"read_default_file": "/path/to/my.cnf",
},
}
}
# my.cnf
[client]
database = NAME
user = USER
password = PASSWORD
default-character-set = utf8
其他幾個MySQLdb 連線選項可能很有用,例如 ssl
、init_command
和 sql_mode
。
設定 sql_mode
¶
sql_mode
選項的預設值包含 STRICT_TRANS_TABLES
。 當資料在插入時被截斷時,該選項會將警告升級為錯誤,因此 Django 強烈建議為 MySQL 啟用嚴格模式,以防止資料遺失 (無論是 STRICT_TRANS_TABLES
還是 STRICT_ALL_TABLES
)。
如果您需要自訂 SQL 模式,您可以像其他 MySQL 選項一樣設定 sql_mode
變數:可以在設定檔中設定,也可以在 DATABASES
中資料庫設定的 OPTIONS
部分中使用 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'"
項目。
隔離層級¶
當執行並行負載時,來自不同工作階段 (例如,處理不同請求的獨立執行緒) 的資料庫交易可能會彼此互動。 這些互動會受到每個工作階段的交易隔離層級影響。 您可以使用在 DATABASES
中資料庫設定的 OPTIONS
部分中的 'isolation_level'
項目,來設定連線的隔離層級。 此項目的有效值是四個標準隔離層級
'read uncommitted'
'read committed'
'repeatable read'
'serializable'
或是 None
,使用伺服器設定的隔離層級。 然而,Django 在讀取已提交而不是 MySQL 的預設值,可重複讀取時效果最佳,並預設為讀取已提交。 可重複讀取可能會造成資料遺失。 特別是,您可能會看到 get_or_create()
引發 IntegrityError
,但該物件不會出現在後續的 get()
呼叫中的情況。
建立表格¶
當 Django 產生綱要時,它不會指定儲存引擎,因此表格將會使用資料庫伺服器設定的預設儲存引擎來建立。 最簡單的解決方案是將資料庫伺服器的預設儲存引擎設定為所需的引擎。
如果您使用託管服務且無法變更伺服器的預設儲存引擎,您有幾個選項。
建立表格後,執行
ALTER TABLE
陳述式,將表格轉換為新的儲存引擎 (例如 InnoDB)ALTER TABLE <tablename> ENGINE=INNODB;
如果您有很多表格,這可能會很乏味。
另一個選項是在建立表格之前,使用 MySQLdb 的
init_command
選項"OPTIONS": { "init_command": "SET default_storage_engine=INNODB", }
這會在連線到資料庫時設定預設的儲存引擎。在您的資料表建立完成後,您應該移除此選項,因為它會將一個僅在資料表建立期間才需要的查詢加入到每個資料庫連線中。
資料表名稱¶
即使在最新版本的 MySQL 中,也存在已知問題,在特定條件下執行特定 SQL 語句時,可能會導致資料表名稱的大小寫被更改。建議您盡可能使用小寫的資料表名稱,以避免此行為可能引起的任何問題。當 Django 從模型自動產生資料表名稱時,會使用小寫的資料表名稱,因此如果您透過 db_table
參數覆寫資料表名稱時,這主要是一個需要考慮的問題。
儲存點¶
Django ORM 和 MySQL(當使用 InnoDB 儲存引擎時)都支援資料庫儲存點。
如果您使用 MyISAM 儲存引擎,請注意,如果您嘗試使用交易 API 的儲存點相關方法,您將會收到資料庫產生的錯誤。原因在於偵測 MySQL 資料庫/資料表的儲存引擎是一項昂貴的操作,因此決定不值得根據此偵測結果動態地將這些方法轉換為無操作。
特定欄位的注意事項¶
字元欄位¶
任何以 VARCHAR
欄位類型儲存的欄位,如果您的欄位使用 unique=True
,其 max_length
可能會被限制為 255 個字元。這會影響 CharField
、SlugField
。有關更多詳細資訊,請參閱 MySQL 文件。
TextField
限制¶
MySQL 只能索引 BLOB
或 TEXT
欄位的前 N 個字元。由於 TextField
沒有定義的長度,因此您不能將其標記為 unique=True
。MySQL 將會報告:「BLOB/TEXT 欄位 '<db_column>' 在金鑰規格中使用時未指定金鑰長度」。
時間和日期時間欄位的秒數小數點支援¶
MySQL 可以儲存秒數小數點,前提是欄位定義包含小數點指示 (例如 DATETIME(6)
)。
如果資料庫伺服器支援,Django 不會升級現有的欄位以包含秒數小數點。如果您想在現有的資料庫上啟用它們,則需要手動更新目標資料庫上的欄位,方法是執行類似以下的命令
ALTER TABLE `your_table` MODIFY `your_datetime_column` DATETIME(6)
TIMESTAMP
欄位¶
如果您使用的是包含 TIMESTAMP
欄位的舊資料庫,則必須設定 USE_TZ = False
以避免資料損毀。inspectdb
會將這些欄位對應到 DateTimeField
,如果您啟用時區支援,MySQL 和 Django 都會嘗試將值從 UTC 轉換為當地時間。
使用 QuerySet.select_for_update()
進行資料列鎖定¶
MySQL 和 MariaDB 不支援 SELECT ... FOR UPDATE
語句的一些選項。如果 select_for_update()
使用了不支援的選項,則會引發 NotSupportedError
。
選項 |
MariaDB |
MySQL |
---|---|---|
|
X (≥10.6) |
X |
|
X |
X |
|
X |
|
|
在 MySQL 上使用 select_for_update()
時,請確保您至少針對唯一約束中包含的一組欄位或僅針對索引涵蓋的欄位來篩選查詢集。否則,將在交易期間對整個資料表取得獨佔寫入鎖定。
自動類型轉換可能會導致非預期的結果¶
當針對字串類型執行查詢,但使用整數值時,MySQL 會在執行比較之前將資料表中所有值的類型強制轉換為整數。如果您的資料表包含值 'abc'
、'def'
,並且您查詢 WHERE mycolumn=0
,則這兩列都會匹配。同樣地,WHERE mycolumn=1
將會匹配值 'abc1'
。因此,Django 中包含的字串類型欄位在查詢中使用之前,將始終將值轉換為字串。
如果您實作直接繼承自 Field
的自訂模型欄位,覆寫 get_prep_value()
,或是使用 RawSQL
、extra()
或 raw()
,您應該確保執行適當的類型轉換。
SQLite 注意事項¶
Django 支援 SQLite 3.31.0 和更高版本。
SQLite 為主要為唯讀或需要較小安裝佔用空間的應用程式提供了一個出色的開發替代方案。但是,與所有資料庫伺服器一樣,您應該了解一些特定於 SQLite 的差異。
子字串匹配和區分大小寫¶
對於所有 SQLite 版本,在嘗試匹配某些字串類型時,會有一些稍微違反直覺的行為。當在 Queryset 中使用 iexact
或 contains
篩選器時,會觸發這些行為。該行為分為兩種情況
1. 對於子字串匹配,所有匹配都是不區分大小寫的。也就是說,像 filter(name__contains="aa")
這樣的篩選器會匹配名稱為 "Aabb"
的名稱。
2. 對於包含 ASCII 範圍之外的字元的字串,即使將不區分大小寫的選項傳遞到查詢中,所有精確的字串匹配都是區分大小寫的。因此,在這些情況下,iexact
篩選器的行為將與 exact
篩選器完全相同。
sqlite.org 上記錄了一些可能的解決方法,但 Django 中的預設 SQLite 後端並未使用它們,因為要穩健地整合它們相當困難。因此,Django 公開了預設的 SQLite 行為,您在執行不區分大小寫或子字串篩選時應該要注意這一點。
Decimal 處理¶
SQLite 沒有真正的十進制內部類型。十進制值會在內部轉換為 REAL
資料類型(8 位元組 IEEE 浮點數),如SQLite 資料類型文件中所述,因此它們不支援正確四捨五入的十進制浮點數算術。
「資料庫已鎖定」錯誤¶
SQLite 的設計目標是輕量級資料庫,因此無法支援高並發。 OperationalError: database is locked
錯誤表示您的應用程式正在經歷比預設配置的 sqlite
所能處理的更高並發量。此錯誤表示一個執行緒或程序對資料庫連線擁有獨佔鎖,而另一個執行緒等待鎖釋放時逾時。
Python 的 SQLite 包裝器具有預設的逾時值,該值決定第二個執行緒在逾時並引發 OperationalError: database is locked
錯誤之前,允許等待鎖定的時間長度。
如果遇到此錯誤,您可以透過以下方式解決:
切換到另一個資料庫後端。在某個時間點,SQLite 對於現實世界的應用程式來說變得太「輕量」了,而這些並發錯誤表示您已達到該點。
重寫程式碼以減少並發,並確保資料庫交易是短暫的。
透過設定
timeout
資料庫選項來增加預設逾時值。"OPTIONS": { # ... "timeout": 20, # ... }
這會使 SQLite 在拋出「資料庫已鎖定」錯誤之前等待更長的時間;它實際上不會真正解決這些錯誤。
交易行為¶
SQLite 支援三種交易模式:DEFERRED
、IMMEDIATE
和 EXCLUSIVE
。
預設值為 DEFERRED
。如果您需要使用不同的模式,請在您的資料庫配置中的 OPTIONS
部分中設定,例如在 DATABASES
中設定。
"OPTIONS": {
# ...
"transaction_mode": "IMMEDIATE",
# ...
}
為了確保您的交易在引發「資料庫已鎖定」錯誤之前等待到 timeout
,請將交易模式變更為 IMMEDIATE
。
為了在使用 IMMEDIATE
和 EXCLUSIVE
時獲得最佳效能,交易應盡可能簡短。對於您的所有視圖來說,這可能很難保證,因此在這種情況下不建議使用 ATOMIC_REQUESTS
。
有關更多資訊,請參閱 SQLite 中的交易。
QuerySet.select_for_update()
不支援¶
SQLite 不支援 SELECT ... FOR UPDATE
語法。呼叫它將沒有任何效果。
使用 QuerySet.iterator()
時的隔離¶
當在使用 QuerySet.iterator()
迭代時修改表格時,SQLite 中的隔離中描述了一些特殊注意事項。如果在迴圈內新增、變更或刪除一行,則該行可能出現或可能不出現,或者在從迭代器獲取的後續結果中可能出現兩次。您的程式碼必須處理此情況。
在 SQLite 上啟用 JSON1 擴充功能¶
若要在 SQLite 上使用 JSONField
,您需要在 Python 的 sqlite3
程式庫上啟用 JSON1 擴充功能。如果您的安裝未啟用擴充功能,則會引發系統錯誤(fields.E180
)。
若要啟用 JSON1 擴充功能,您可以按照 wiki 頁面上的指示進行操作。
注意
JSON1 擴充功能在 SQLite 3.38+ 上預設啟用。
設定 pragma 選項¶
可以使用 Pragma 選項,透過在 OPTIONS
中的 init_command
設定連線時的選項。這個設定位在 DATABASES
中的資料庫配置中。以下範例說明如何啟用同步寫入的額外耐用性並變更 cache_size
。
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
# ...
"OPTIONS": {
"init_command": "PRAGMA synchronous=3; PRAGMA cache_size=2000;",
},
}
}
Oracle 注意事項¶
Django 支援 Oracle Database Server 19c 及更高版本。需要 1.3.2 或更高版本的 oracledb Python 驅動程式。
自 5.0 版本起已棄用: 對 cx_Oracle
的支援已棄用。
為了使 python manage.py migrate
命令正常運作,您的 Oracle 資料庫使用者必須擁有執行以下命令的權限。
CREATE TABLE
CREATE SEQUENCE
CREATE PROCEDURE
CREATE TRIGGER
若要執行專案的測試套件,使用者通常需要這些額外權限。
CREATE USER
ALTER USER
DROP USER
CREATE TABLESPACE
DROP TABLESPACE
CREATE SESSION WITH ADMIN OPTION
CREATE TABLE WITH ADMIN OPTION
CREATE SEQUENCE WITH ADMIN OPTION
CREATE PROCEDURE WITH ADMIN OPTION
CREATE TRIGGER WITH ADMIN OPTION
雖然 RESOURCE
角色具有所需的 CREATE TABLE
、CREATE SEQUENCE
、CREATE PROCEDURE
和 CREATE TRIGGER
權限,並且授予 RESOURCE WITH ADMIN OPTION
的使用者可以授予 RESOURCE
,但這樣的使用者無法授予個別權限(例如 CREATE TABLE
),因此 RESOURCE WITH ADMIN OPTION
通常不足以執行測試。
某些測試套件也會建立視圖或實體化視圖;若要執行這些視圖或實體化視圖,使用者也需要 CREATE VIEW WITH ADMIN OPTION
和 CREATE MATERIALIZED VIEW WITH ADMIN OPTION
權限。特別是,Django 自己的測試套件需要此權限。
所有這些權限都包含在 DBA 角色中,該角色適用於私人開發人員的資料庫。
Oracle 資料庫後端使用 SYS.DBMS_LOB
和 SYS.DBMS_RANDOM
套件,因此您的使用者將需要對其具有執行權限。它通常預設可供所有使用者存取,但如果不是,您需要像這樣授予權限。
GRANT EXECUTE ON SYS.DBMS_LOB TO user;
GRANT EXECUTE ON SYS.DBMS_RANDOM TO user;
連線至資料庫¶
若要使用 Oracle 資料庫的服務名稱進行連線,您的 settings.py
檔案應如下所示。
DATABASES = {
"default": {
"ENGINE": "django.db.backends.oracle",
"NAME": "xe",
"USER": "a_user",
"PASSWORD": "a_password",
"HOST": "",
"PORT": "",
}
}
在這種情況下,您應將 HOST
和 PORT
都保留為空白。但是,如果您不使用 tnsnames.ora
檔案或類似的命名方法,並想要使用 SID(在此範例中為「xe」)進行連線,則請同時填寫 HOST
和 PORT
,如下所示。
DATABASES = {
"default": {
"ENGINE": "django.db.backends.oracle",
"NAME": "xe",
"USER": "a_user",
"PASSWORD": "a_password",
"HOST": "dbprod01ned.mycompany.com",
"PORT": "1540",
}
}
您應該同時提供 HOST
和 PORT
,或者將它們都保留為空字串。Django 將根據該選擇使用不同的連線描述符。
完整 DSN 和簡易連線¶
如果 HOST
和 PORT
都為空,則可以在 NAME
中使用完整的 DSN 或簡易連線字串。例如,當使用 RAC 或不需要 tnsnames.ora
的可插拔資料庫時,需要此格式。
簡易連線字串範例
"NAME": "localhost:1521/orclpdb1"
完整 DSN 字串範例
"NAME": (
"(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))"
"(CONNECT_DATA=(SERVICE_NAME=orclpdb1)))"
)
執行緒選項¶
如果您計劃在多執行緒環境中執行 Django(例如,在任何現代作業系統上使用預設 MPM 模組的 Apache),則您必須將 Oracle 資料庫配置的 threaded
選項設定為 True
。
"OPTIONS": {
"threaded": True,
}
如果沒有這樣做,可能會導致崩潰和其他奇怪的行為。
INSERT … RETURNING INTO¶
預設情況下,Oracle 後端使用 RETURNING INTO
子句來有效率地擷取插入新列時 AutoField
的值。在某些不尋常的設定中,例如插入遠端表格,或插入具有 INSTEAD OF
觸發器的視圖時,此行為可能會導致 DatabaseError
。可以透過將資料庫配置的 use_returning_into
選項設定為 False
來停用 RETURNING INTO
子句。
"OPTIONS": {
"use_returning_into": False,
}
在這種情況下,Oracle 後端將使用單獨的 SELECT
查詢來擷取 AutoField
值。
命名問題¶
Oracle 對名稱長度設有 30 個字元的限制。為了配合此限制,後端會截斷資料庫識別符以符合長度,並將截斷名稱的最後四個字元替換為可重複的 MD5 雜湊值。此外,後端會將資料庫識別符轉換為全部大寫。
為了防止這些轉換(通常僅在處理舊版資料庫或存取屬於其他使用者的表格時才需要),請使用帶引號的名稱作為 db_table
的值。
class LegacyModel(models.Model):
class Meta:
db_table = '"name_left_in_lowercase"'
class ForeignModel(models.Model):
class Meta:
db_table = '"OTHER_USER"."NAME_ONLY_SEEMS_OVER_30"'
帶引號的名稱也可以用於 Django 的其他支援資料庫後端;但除了 Oracle 之外,引號沒有任何作用。
在執行 migrate
時,如果某些 Oracle 關鍵字被用作模型欄位的名稱或 db_column
選項的值,則可能會遇到 ORA-06552
錯誤。 Django 會引用查詢中使用的所有識別符,以防止大多數此類問題,但當 Oracle 資料類型被用作欄位名稱時,仍然可能發生此錯誤。特別注意避免使用名稱 date
、timestamp
、number
或 float
作為欄位名稱。
NULL 和空字串¶
Django 通常偏好使用空字串 (''
) 而不是 NULL
,但 Oracle 將兩者視為相同。為了規避此問題,Oracle 後端會忽略欄位上明確的 null
選項(該欄位可能的值為空字串),並產生 DDL,如同 null=True
一樣。從資料庫提取資料時,會假設這些欄位中的 NULL
值實際上表示空字串,並會靜默地轉換資料以反映此假設。
TextField
的限制¶
Oracle 後端將 TextFields
儲存為 NCLOB
欄位。 Oracle 對於 LOB 欄位的使用施加了一些限制。
LOB 欄位不得用作主鍵。
LOB 欄位不得用於索引。
LOB 欄位不得用於
SELECT DISTINCT
清單中。這表示嘗試在包含TextField
欄位的模型上使用QuerySet.distinct
方法,在針對 Oracle 執行時會導致ORA-00932
錯誤。作為一種解決方法,請搭配distinct()
使用QuerySet.defer
方法,以防止TextField
欄位被包含在SELECT DISTINCT
清單中。
子類化內建資料庫後端¶
Django 內建資料庫後端。您可以子類化現有的資料庫後端,以修改其行為、功能或組態。
例如,假設您需要變更單一資料庫功能。首先,您必須建立一個新目錄,其中包含 base
模組。例如
mysite/
...
mydbengine/
__init__.py
base.py
base.py
模組必須包含一個名為 DatabaseWrapper
的類別,該類別會子類化 django.db.backends
模組中的現有引擎。以下是子類化 PostgreSQL 引擎以變更功能類別 allows_group_by_selected_pks_on_model
的範例
mysite/mydbengine/base.py
¶from django.db.backends.postgresql import base, features
class DatabaseFeatures(features.DatabaseFeatures):
def allows_group_by_selected_pks_on_model(self, model):
return True
class DatabaseWrapper(base.DatabaseWrapper):
features_class = DatabaseFeatures
最後,您必須在 settings.py
檔案中指定 DATABASE-ENGINE
DATABASES = {
"default": {
"ENGINE": "mydbengine",
# ...
},
}
您可以在 django/db/backends 中查看目前資料庫引擎的清單。
使用第三方資料庫後端¶
除了官方支援的資料庫之外,還有第三方提供的後端,讓您可以在 Django 中使用其他資料庫
這些非官方後端所支援的 Django 版本和 ORM 功能差異很大。有關這些非官方後端的特定功能以及任何支援查詢的問題,應直接向每個第三方專案提供的支援管道提出。