データベース
Djangoは、次のデータベースを公式にサポートしています。
サードパーティによって提供されるデータベースバックエンドも多数あります。
Djangoは、すべてのデータベースバックエンドで可能な限り多くの機能をサポートしようとします。 ただし、すべてのデータベースバックエンドが類似しているわけではなく、サポートする機能と安全に実行できる前提条件について設計上の決定を下す必要がありました。
このファイルは、Djangoの使用に関連する可能性のあるいくつかの機能について説明しています。 サーバー固有のドキュメントやリファレンスマニュアルの代わりになるものではありません。
一般的注意事項
持続的接続
持続的接続は、各要求でデータベースへの接続を再確立するオーバーヘッドを回避します。 これらは、接続の最大存続期間を定義する:setting: `CONN_MAX_AGE` パラメーターによって制御されます。 データベースごとに個別に設定できます。
デフォルト値は0
で、各要求の終了時にデータベース接続を閉じるという履歴動作を保持します。 持続的接続を有効にするには、:setting: `CONN_MAX_AGE` を正の秒の整数に設定します。 無制限の持続的接続の場合は、None
に設定します。
接続管理
Djangoは、最初にデータベースクエリを実行するときに、データベースへの接続を開きます。 この接続を開いたままにして、後続のリクエストで再利用します。 Djangoは、:setting: `CONN_MAX_AGE` で定義された最大経過時間を超えるか、使用できなくなったときに接続を閉じます。
詳細には、Djangoは、データベースへの接続が必要で、まだ接続がない場合はいつでも、データベースへの接続を自動的に開きます。これが最初の接続であるか、前の接続が閉じられたためです。
各リクエストの開始時に、Djangoは最大経過時間に達した場合、接続を閉じます。 データベースがアイドル状態の接続をしばらくして終了する場合は、:setting: `CONN_MAX_AGE` を低い値に設定して、Djangoがデータベースサーバーによって終了された接続を使用しないようにする必要があります。 (この問題は、トラフィックが非常に少ないサイトにのみ影響する可能性があります。)
各リクエストの終了時に、Djangoは、接続が最大経過時間に達した場合、または回復不能なエラー状態にある場合、接続を閉じます。 リクエストの処理中にデータベースエラーが発生した場合、Djangoは接続がまだ機能しているかどうかを確認し、機能していない場合は閉じます。 したがって、データベースエラーは最大で1つの要求に影響します。 接続が使用できなくなった場合、次のリクエストは新しい接続を取得します。
警告
各スレッドは独自の接続を維持するため、データベースは少なくともワーカースレッドと同じ数の同時接続をサポートする必要があります。
データベースが外部システムのデータベースであるため、またはキャッシュのおかげで、ビューの大部分がデータベースにアクセスできない場合があります。 このような場合、再利用される可能性が低い接続を維持することは意味がないため、:setting: `CONN_MAX_AGE` を低い値または0
に設定する必要があります。 これにより、このデータベースへの同時接続の数を少なく保つことができます。
開発サーバーは、処理するリクエストごとに新しいスレッドを作成し、持続的接続の影響を無効にします。 開発中にそれらを有効にしないでください。
Djangoはデータベースへの接続を確立するときに、使用されているバックエンドに応じて適切なパラメーターを設定します。 持続的接続を有効にすると、この設定がリクエストごとに繰り返されることはなくなります。 接続の分離レベルやタイムゾーンなどのパラメーターを変更する場合は、各リクエストの終了時にDjangoのデフォルトを復元するか、各リクエストの開始時に適切な値を強制するか、永続的な接続を無効にする必要があります。
エンコーディング
Djangoは、すべてのデータベースがUTF-8エンコーディングを使用していることを前提としています。 他のエンコーディングを使用すると、Djangoで有効なデータのデータベースから「値が長すぎる」エラーなどの予期しない動作が発生する可能性があります。 データベースを正しく設定する方法については、以下のデータベース固有の注意事項を参照してください。
PostgreSQLノート
DjangoはPostgreSQL9.6以降をサポートしています。 psycopg2 2.5.4以降が必要ですが、最新のリリースをお勧めします。
PostgreSQLの構成の最適化
Djangoは、データベース接続のために次のパラメーターを必要とします。
client_encoding
:'UTF8'
、default_transaction_isolation
:デフォルトでは'read committed'
、または接続オプションで設定された値(以下を参照)、- *;
timezone
:- *;* いつ :setting: `USE_TZ` は
True
、'UTC'
デフォルト、または :setting: `TIME_ZONE ` 接続に設定された値、
- :setting: `USE_TZ` が
False
の場合、グローバル:setting:` TIME_ZONE` 設定の値。
- :setting: `USE_TZ` が
- *;* いつ :setting: `USE_TZ` は
これらのパラメーターがすでに正しい値を持っている場合、Djangoは新しい接続ごとにそれらを設定しないため、パフォーマンスがわずかに向上します。 postgresql.conf
で直接構成することも、 ALTER ROLE を使用してデータベースユーザーごとに便利に構成することもできます。
Djangoはこの最適化なしで問題なく動作しますが、新しい接続ごとにいくつかの追加クエリを実行してこれらのパラメーターを設定します。
分離レベル
PostgreSQL自体と同様に、DjangoはデフォルトでREAD COMMITTED
分離レベルになります。 REPEATABLE READ
やSERIALIZABLE
などのより高い分離レベルが必要な場合は、:settingのデータベース構成の:setting: `OPTIONS` 部分で設定します。 : `データベース` :
import psycopg2.extensions
DATABASES = {
# ...
'OPTIONS': {
'isolation_level': psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE,
},
}
ノート
より高い分離レベルでは、アプリケーションは、シリアル化の失敗で発生した例外を処理できるように準備する必要があります。 このオプションは、高度な用途向けに設計されています。
varchar列とtext列のインデックス
モデルフィールドでdb_index=True
を指定すると、Djangoは通常単一のCREATE INDEX
ステートメントを出力します。 ただし、フィールドのデータベースタイプがvarchar
またはtext
の場合(たとえば、CharField
、FileField
、およびTextField
で使用されます) )、Djangoは、列に適切な PostgreSQLオペレータークラスを使用する追加のインデックスを作成します。 contains
およびstartswith
ルックアップタイプで行われるように、SQLでLIKE
演算子を使用するルックアップを正しく実行するには、追加のインデックスが必要です。
サーバー側カーソル
QuerySet.iterator()を使用すると、Djangoはサーバー側カーソルを開きます。 デフォルトでは、PostgreSQLはカーソルクエリの結果の最初の10 % o fのみがフェッチされると想定しています。 クエリプランナーは、クエリの計画に費やす時間が少なくて済み、結果をより早く返し始めますが、結果が10 % o fを超えると、パフォーマンスが低下する可能性があります。 カーソルクエリ用に取得される行数に関するPostgreSQLの仮定は、 cursor_tuple_fraction オプションで制御されます。
トランザクションプーリングとサーバー側カーソル
トランザクションプーリングモードでの接続プールの使用(例: PgBouncer )では、その接続のサーバー側カーソルを無効にする必要があります。
サーバー側カーソルは接続に対してローカルであり、トランザクションの終了時に開いたままになります。 :setting: `AUTOCOMMIT ` はTrue
。 後続のトランザクションは、サーバー側カーソルからより多くの結果をフェッチしようとする場合があります。 トランザクションプーリングモードでは、後続のトランザクションが同じ接続を使用するという保証はありません。 別の接続が使用されている場合、サーバー側カーソルは作成された接続でのみアクセスできるため、トランザクションがサーバー側カーソルを参照するとエラーが発生します。
1つの解決策は、接続のサーバー側カーソルを無効にすることです。 :setting: `データベース` 設定することにより :setting: `DISABLE_SERVER_SIDE_CURSORS ` にTrue
。
トランザクションプーリングモードでサーバー側カーソルを利用するには、サーバー側カーソルを使用するクエリを実行するために、データベースへの別の接続を設定できます。 この接続は、データベースに直接接続するか、セッションプールモードの接続プールに接続する必要があります。
別のオプションは、サーバー側カーソルを使用して各QuerySet
を atomic()ブロックでラップすることです。これは、トランザクションの間、autocommit
を無効にするためです。 このように、サーバー側カーソルはトランザクションの期間中のみ存続します。
自動インクリメントする主キーの値を手動で指定する
Djangoは、PostgreSQLの SERIALデータ型を使用して、自動インクリメントする主キーを格納します。 SERIAL
列には、次に使用可能な値を追跡するシーケンスからの値が入力されます。 自動インクリメントフィールドに値を手動で割り当てても、フィールドのシーケンスは更新されないため、後で競合が発生する可能性があります。 例えば:
>>> 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.
このような値を指定する必要がある場合は、後でシーケンスをリセットして、テーブルに既に存在する値を再利用しないようにします。 :djadmin: `sqlsequencereset` 管理コマンドは、それを行うためのSQLステートメントを生成します。
データベーステンプレートをテストする
あなたは使用することができます :setting: `TEST ['TEMPLATE'] ` 指定する設定レンプレート (例えば 'template0'
)からテストデータベースを作成します。
非耐久性の設定でテスト実行を高速化
PostgreSQLを非耐久性に設定することでテストの実行時間を短縮できます。
警告
これは危険です。サーバーがクラッシュしたり電源が切れたりした場合に、データベースがデータの損失や破損の影響を受けやすくなります。 これは、クラスター内のすべてのデータベースのコンテンツ全体を簡単に復元できる開発マシンでのみ使用してください。
MariaDBノート
DjangoはMariaDB10.2以降をサポートしています。
MariaDBを使用するには、2つの間で共有されるMySQLバックエンドを使用します。 詳細については、 MySQLノートを参照してください。
MySQLノート
バージョンサポート
DjangoはMySQL5.7以降をサポートしています。
Djangoのinspectdb
機能は、information_schema
データベースを使用します。このデータベースには、すべてのデータベーススキーマに関する詳細データが含まれています。
Djangoは、データベースがUnicode(UTF-8エンコーディング)をサポートすることを期待しており、トランザクションと参照整合性を適用するタスクをデータベースに委任します。 MyISAMストレージエンジンを使用する場合、後者の2つはMySQLによって実際には強制されないという事実に注意することが重要です。次のセクションを参照してください。
ストレージエンジン
MySQLにはいくつかのストレージエンジンがあります。 サーバー構成でデフォルトのストレージエンジンを変更できます。
MySQLのデフォルトのストレージエンジンは InnoDB です。 このエンジンは完全にトランザクションであり、外部キー参照をサポートします。 これが推奨される選択です。 ただし、InnoDB自動インクリメントカウンターはAUTO_INCREMENT
値を記憶していないため、MySQLの再起動時に失われ、代わりに「max(id)+1」として再作成されます。 これにより、 AutoField 値が誤って再利用される可能性があります。
MyISAM の主な欠点は、トランザクションをサポートしていないか、外部キー制約を適用していないことです。
MySQL DBAPIドライバー
MySQLには、 PEP 249 で説明されているPythonデータベースAPIを実装するいくつかのドライバーがあります。
- mysqlclient はネイティブドライバーです。 推奨される選択です。
- MySQL Connector / Python は、Oracleの純粋なPythonドライバーであり、MySQLクライアントライブラリや標準ライブラリ外のPythonモジュールを必要としません。
これらのドライバーはスレッドセーフであり、接続プールを提供します。
Djangoには、DB APIドライバーに加えて、ORMからデータベースドライバーにアクセスするためのアダプターが必要です。 Djangoはmysqlclient用のアダプターを提供しますが、MySQL Connector / Pythonには独自のが含まれています。
MySQLコネクタ/ Python
MySQL Connector / Pythonは、ダウンロードページから入手できます。 Djangoアダプターは、バージョン1.1.X以降で使用できます。 Djangoの最新リリースをサポートしていない可能性があります。
タイムゾーンの定義
Djangoのタイムゾーンサポートを使用する場合は、 mysql_tzinfo_to_sql を使用してタイムゾーンテーブルをMySQLデータベースにロードします。 これは、データベースごとではなく、MySQLサーバーに対して1回だけ実行する必要があります。
データベースの作成
コマンドラインツールと次の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
が発生します。
バージョン3.2で変更:フィールドのデータベース照合の設定のサポートが追加されました。
データベースへの接続
設定ドキュメントを参照してください。
接続設定は次の順序で使用されます。
- :setting: `OPTIONS` 。
- :setting: `NAME` 、:setting:` USER` 、:setting: `PASSWORD` 、:setting:` HOST` [X101X ]、:setting: `PORT`
- MySQLオプションファイル。
つまり、:setting: `OPTIONS` でデータベースの名前を設定すると、:setting:` 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
ssl
、init_command
、sql_mode
など、他のいくつかの MySQLdb接続オプションが役立つ場合があります。
設定sql_mode
MySQL 5.7以降、sql_mode
オプションのデフォルト値にはSTRICT_TRANS_TABLES
が含まれています。 このオプションは、挿入時にデータが切り捨てられると警告をエラーにエスカレートするため、Djangoは、データの損失を防ぐためにMySQLの厳密モードをアクティブにすることを強くお勧めします(STRICT_TRANS_TABLES
またはSTRICT_ALL_TABLES
)。
SQLモードをカスタマイズする必要がある場合は、他のMySQLオプションと同様にsql_mode
変数を設定できます。構成ファイルまたは:setting: `OPTIONSのエントリ'init_command': "SET sql_mode='STRICT_TRANS_TABLES'"
を使用します。 :setting: `DATABASES` のデータベース構成の` 部分。
分離レベル
同時ロードを実行する場合、異なるセッション(たとえば、異なる要求を処理する別々のスレッド)からのデータベーストランザクションが相互に作用する可能性があります。 これらの相互作用は、各セッションのトランザクション分離レベルの影響を受けます。 :setting: `DATABASES` のデータベース構成の:setting:` OPTIONS` 部分にある'isolation_level'
エントリを使用して、接続の分離レベルを設定できます。 このエントリの有効な値は、次の4つの標準分離レベルです。
'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データベース/テーブルのストレージエンジンの検出はコストのかかる操作であるため、このような検出の結果に基づいて、これらのメソッドをno-opに動的に変換する価値がないと判断されたためです。
特定の分野に関する注記
文字フィールド
VARCHAR
列タイプで格納されるフィールドでは、フィールドにunique=True
を使用している場合、max_length
が255文字に制限される場合があります。 これは、 CharField 、 SlugField に影響します。 詳細については、 MySQLドキュメントを参照してください。
TextFieldの制限
MySQLは、BLOB
またはTEXT
列の最初のN文字のみにインデックスを付けることができます。 TextField
には長さが定義されていないため、unique=True
としてマークすることはできません。 MySQLは次のように報告します:「BLOB / TEXT列」 「キーの長さなしでキー仕様で使用されます」。
TimeフィールドとDateTimeフィールドの秒の小数部のサポート
列定義に小数表示が含まれている場合、MySQLは小数秒を格納できます(例: DATETIME(6)
)。
Djangoは、データベースサーバーがサポートしている場合、既存の列をアップグレードして秒の小数部を含めることはありません。 既存のデータベースでそれらを有効にする場合は、次のようなコマンドを実行して、ターゲットデータベースの列を手動で更新する必要があります。
ALTER TABLE `your_table` MODIFY `your_datetime_column` DATETIME(6)
TIMESTAMP列
を含むレガシーデータベースを使用している場合TIMESTAMP
列、設定する必要があります :setting: `USE_TZ = False ` データの破損を避けるため。 :djadmin: `inspectdb` はこれらの列を DateTimeField にマップし、タイムゾーンサポートを有効にすると、MySQLとDjangoの両方が値をUTCから現地時間に変換しようとします。
QuerySet.select_for_update()による行ロック
MySQLとMariaDBは、SELECT ... FOR UPDATE
ステートメントの一部のオプションをサポートしていません。 select_for_update()
がサポートされていないオプションとともに使用されると、 NotSupportedError が発生します。
オプション | MariaDB | MySQL |
---|---|---|
SKIP LOCKED
|
X(≥8.0.1) | |
NOWAIT
|
X(≥10.3) | X(≥8.0.1) |
OF
|
X(≥8.0.1) | |
NO KEY
|
MySQLでselect_for_update()
を使用する場合は、少なくとも一意の制約に含まれるフィールドのセットに対して、またはインデックスでカバーされるフィールドに対してのみクエリセットをフィルタリングするようにしてください。 それ以外の場合は、トランザクションの期間中、テーブル全体で排他書き込みロックが取得されます。
自動型キャストは予期しない結果を引き起こす可能性があります
文字列型に対してクエリを実行するが、整数値を使用する場合、MySQLは、比較を実行する前に、テーブル内のすべての値の型を整数に強制します。 テーブルに値'abc'
、'def'
が含まれていて、WHERE mycolumn=0
をクエリすると、両方の行が一致します。 同様に、WHERE mycolumn=1
は値'abc1'
と一致します。 したがって、Djangoに含まれる文字列型フィールドは、クエリで使用する前に常に値を文字列にキャストします。
Field から直接継承するカスタムモデルフィールドを実装する場合、 get_prep_value()をオーバーライドする場合、または RawSQL 、 extra()を使用する場合、または raw()の場合、適切な型キャストを実行していることを確認する必要があります。
SQLiteノート
DjangoはSQLite3.9.0以降をサポートしています。
SQLite は、主に読み取り専用であるか、より小さなインストールフットプリントを必要とするアプリケーションに優れた開発代替手段を提供します。 ただし、すべてのデータベースサーバーと同様に、SQLiteに固有のいくつかの違いに注意する必要があります。
部分文字列の照合と大文字と小文字の区別
すべてのSQLiteバージョンで、一部のタイプの文字列を照合しようとすると、少し直感に反する動作があります。 これらは、クエリセットで:lookup: `iexact` または:lookup:` contains` フィルターを使用するとトリガーされます。 動作は2つのケースに分かれます。
1. サブストリングマッチングの場合、すべてのマッチングは大文字と小文字を区別せずに行われます。 つまり、filter(name__contains="aa")
などのフィルターは"Aabb"
の名前と一致します。
2. ASCII範囲外の文字を含む文字列の場合、大文字と小文字を区別しないオプションがクエリに渡された場合でも、文字列の完全一致はすべて大文字と小文字を区別して実行されます。 したがって、:lookup: `iexact` フィルターは、これらの場合、:lookup:` excate` フィルターとまったく同じように動作します。
これに対するいくつかの可能な回避策は sqlite.org に文書化されていますが、それらを組み込むことは堅牢に行うのがかなり難しいため、DjangoのデフォルトのSQLiteバックエンドでは使用されません。 したがって、DjangoはデフォルトのSQLiteの動作を公開します。大文字と小文字を区別しない、または部分文字列のフィルタリングを行う場合は、これに注意する必要があります。
10進数の処理
SQLiteには実際の10進数の内部型はありません。 SQLiteデータ型のドキュメントで説明されているように、10進値は内部でREAL
データ型(8バイトのIEEE浮動小数点数)に変換されるため、正しく丸められた10進浮動小数点はサポートされません。ポイント演算。
「データベースがロックされています」エラー
SQLiteは軽量のデータベースであることが意図されているため、高レベルの同時実行性をサポートすることはできません。 OperationalError: database is locked
エラーは、アプリケーションでsqlite
がデフォルト構成で処理できるよりも多くの同時実行性が発生していることを示します。 このエラーは、1つのスレッドまたはプロセスがデータベース接続に排他ロックを持っており、別のスレッドがロックが解放されるのを待ってタイムアウトしたことを意味します。
PythonのSQLiteラッパーには、2番目のスレッドがタイムアウトする前にロックを待機できる時間を決定するデフォルトのタイムアウト値があり、OperationalError: database is locked
エラーが発生します。
このエラーが発生した場合は、次の方法で解決できます。
別のデータベースバックエンドに切り替えます。 ある時点で、SQLiteは実際のアプリケーションには「ライト」になりすぎます。このような同時実行エラーは、その時点に到達したことを示します。
コードを書き直して同時実行性を減らし、データベーストランザクションが短命であることを確認します。
timeout
データベースオプションを設定して、デフォルトのタイムアウト値を増やします。'OPTIONS': { # ... 'timeout': 20, # ... }
これにより、SQLiteは「データベースがロックされています」というエラーをスローする前に少し長く待機します。 それらを解決するために実際には何もしません。
QuerySet.select_for_update()はサポートされていません
SQLiteはSELECT ... FOR UPDATE
構文をサポートしていません。 それを呼んでも効果はありません。
生のクエリの「pyformat」パラメータスタイルはサポートされていません
ほとんどのバックエンドでは、生のクエリ(Manager.raw()
またはcursor.execute()
)は「pyformat」パラメータースタイルを使用できます。このスタイルでは、クエリのプレースホルダーは'%(name)s'
として指定され、パラメーターは次のように渡されます。リストではなく辞書。 SQLiteはこれをサポートしていません。
QuerySet.iterator()使用時の分離
QuerySet.iterator()を使用してテーブルを反復処理するときにテーブルを変更する場合は、 Isolation In SQLite で説明されている特別な考慮事項があります。 ループ内で行が追加、変更、または削除された場合、その行は、イテレーターからフェッチされた後続の結果で表示される場合と表示されない場合、または2回表示される場合があります。 コードでこれを処理する必要があります。
Oracleノート
Djangoは、 Oracle Database Server バージョン12.2以降をサポートします。 cx_Oracle Pythonドライバーのバージョン6.0以降が必要です。
python manage.py migrate
コマンドを機能させるには、Oracleデータベースユーザーに次のコマンドを実行する権限が必要です。
- CREATE TABLE
- シーケンスの作成
- 手順の作成
- CREATE TRIGGER
プロジェクトのテストスイートを実行するには、通常、ユーザーは次の追加特権を必要とします。
- ユーザーを作成
- ALTER USER
- ドロップユーザー
- CREATETABLESPACE
- DROPTABLESPACE
- 管理者オプションでセッションを作成する
- 管理オプションを使用してテーブルを作成する
- 管理オプションを使用してシーケンスを作成する
- 管理オプションを使用してプロシージャを作成する
- 管理オプションを使用してトリガーを作成する
RESOURCE
ロールには、必要なCREATE TABLE
、CREATE SEQUENCE
、CREATE PROCEDURE
、およびCREATE TRIGGER
特権があり、ユーザーには [ X124X]は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': '',
}
}
この場合、:setting: `HOST` と:setting:` PORT` の両方を空のままにしておく必要があります。 ただし、tnsnames.ora
ファイルまたは同様の命名方法を使用せず、SID(この例では「xe」)を使用して接続する場合は、:setting: `HOST`の両方に入力します。 と:setting: `PORT` のように:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.oracle',
'NAME': 'xe',
'USER': 'a_user',
'PASSWORD': 'a_password',
'HOST': 'dbprod01ned.mycompany.com',
'PORT': '1540',
}
}
:setting: `HOST` と:setting:` PORT` の両方を指定するか、両方を空の文字列のままにしておく必要があります。 Djangoは、その選択に応じて異なる接続記述子を使用します。
フルDSNとEasyConnect
:setting: `HOST` と:setting:` PORT` の両方の場合、:setting: `NAME` で完全なDSNまたはEasyConnect文字列を使用できます。空です。 この形式は、たとえばtnsnames.ora
なしでRACまたはプラグ可能なデータベースを使用する場合に必要です。
Easy Connect文字列の例:
'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,
},
これを怠ると、クラッシュやその他の奇妙な動作が発生する可能性があります。
挿入…に戻る
デフォルトでは、OracleバックエンドはRETURNING INTO
句を使用して、新しい行を挿入するときにAutoField
の値を効率的に取得します。 この動作により、リモートテーブルに挿入する場合や、INSTEAD OF
トリガーを使用してビューに挿入する場合など、特定の異常な設定でDatabaseError
が発生する場合があります。 RETURNING INTO
句は、データベース構成のuse_returning_into
オプションをFalse
に設定することで無効にできます。
'OPTIONS': {
'use_returning_into': False,
},
この場合、Oracleバックエンドは個別のSELECT
クエリを使用してAutoField
値を取得します。
命名の問題
Oracleでは、名前の長さを30文字に制限しています。 これに対応するために、バックエンドはデータベース識別子を切り捨てて、切り捨てられた名前の最後の4文字を繰り返し可能な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
オプションを無視し、null=True
のようにDDLを生成します。 データベースからフェッチする場合、これらのフィールドの1つにあるNULL
値は実際には空の文字列を意味すると想定され、データはこの想定を反映するようにサイレントに変換されます。
TextFieldの制限
Oracleバックエンドは、TextFields
をNCLOB
列として格納します。 Oracleは、一般に、このようなLOB列の使用にいくつかの制限を課しています。
- LOB列を主キーとして使用することはできません。
- LOB列はインデックスで使用できません。
SELECT DISTINCT
リストではLOB列を使用できません。 つまり、TextField
列を含むモデルでQuerySet.distinct
メソッドを使用しようとすると、Oracleに対して実行するとORA-00932
エラーが発生します。 回避策として、QuerySet.defer
メソッドをdistinct()
と組み合わせて使用し、TextField
列がSELECT DISTINCT
リストに含まれないようにします。
組み込みデータベースバックエンドのサブクラス化
Djangoにはデータベースバックエンドが組み込まれています。 既存のデータベースバックエンドをサブクラス化して、その動作、機能、または構成を変更できます。
たとえば、単一のデータベース機能を変更する必要があるとします。 まず、base
モジュールを含む新しいディレクトリを作成する必要があります。 例えば:
mysite/
...
mydbengine/
__init__.py
base.py
base.py
モジュールには、django.db.backends
モジュールから既存のエンジンをサブクラス化するDatabaseWrapper
という名前のクラスが含まれている必要があります。 PostgreSQLエンジンをサブクラス化してフィーチャクラスallows_group_by_selected_pks_on_model
を変更する例を次に示します。
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
ファイルで:setting: `DATABASE-ENGINE` を指定する必要があります。
DATABASES = {
'default': {
'ENGINE': 'mydbengine',
...
},
}
:source: `django / db / backends` を調べると、データベースエンジンの現在のリストを確認できます。
サードパーティのデータベースバックエンドを使用する
公式にサポートされているデータベースに加えて、サードパーティが提供するバックエンドがあり、Djangoで他のデータベースを使用できます。
これらの非公式バックエンドでサポートされているDjangoのバージョンとORM機能はかなり異なります。 これらの非公式バックエンドの特定の機能に関するクエリは、サポートクエリとともに、各サードパーティプロジェクトが提供するサポートチャネルに送信する必要があります。