.. _ref-databases: ========================== データベースのサポート状況 ========================== :revision-up-to: 8961 (1.0) Django は可能な限り全てのデータベースバックエンドをサポートしようとしていま すが、残念ながら全てのサーバが全く同じ仕様というわけではないので、どの機能 をサポートすべきか、どういった仕様を仮定するかといった設計上の判断を下して います。 このドキュメントでは、このドキュメントでは、 Django を使う上で関係のあるデー タベース機能について説明します。ただし、このドキュメントは特定のデータベー スサーバ向けのドキュメントとして書かれたものではなく、リファレンスマニュア ルでもありません。 .. _mysql-notes: .. _MySQL Notes: MySQL に関する注意 ================== Django はデータベースがトランザクションや参照の一貫性 (referential integrity)、 Unicode (UTF-8 エンコーディング) をサポートしていることを想定 して書かれています。好運なことに、 MySQL_ バージョン 3.23 以降でこれらの機 能全てをサポートしています。従って、 3.23 や 4.0 をバックエンドとして使うの は可能なのですが、 4.1 や 5.0 を使った方がトラブルに巻き込まれにくいでしょ う。 MySQL 4.1 --------- `MySQL 4.1`_ では、文字セットのサポートを大幅に改良しています。 4.1 では、 データベース全体から、テーブル毎、カラム毎にいたるまで個別にデフォルトの文 字セットを指定できます。以前のバージョンでは、サーバ全体に対する文字セット の設定しかできませんでした。また、 4.1 になってはじめてオンザフライで文字セッ トを変更できるようになりました。 4.1 にはビューのサポートもありますが、 Django はまだこの機能をサポートしていません。 MySQL 5.0 --------- `MySQL 5.0`_ では、全てのデータベーススキーマに関する詳細なデータの入った ``information_schema`` というデータベースが追加されました。 ``information_schema`` が存在すると、 Django はこのデータベースに対して ``inspectdb`` 機能を適用します。 5.0 ではまた、ストアドプロシジャのサポート も追加されましたが、 Django はまだこの機能をサポートしていません。 .. _MySQL: http://www.mysql.com/ .. _`MySQL 4.1`: http://dev.mysql.com/doc/refman/4.1/en/index.html .. _`MySQL 5.0`: http://dev.mysql.com/doc/refman/5.0/en/index.html .. _Storage Engines: ストレージエンジン ------------------ MySQL は複数の `ストレージエンジン`_ (以前はテーブルタイプ: table type と呼ばれていたもの) を選択できます。 デフォルトのストレージエンジンはサーバ設定で変更できます。 デフォルトのストレージエンジンは MyISAM_ です。 MyISAM の短所は、現状ではト ランザクションや外部キーをサポートしていないという点です。一方、 MyISAM は、 現状で、全文インデクスの生成や全文検索をサポートしている唯一のストレージエ ンジンです。 InnoDB_ エンジンは完全なトランザクション機能と外部キー参照をサポートしてい ます。 BDB_ エンジンは InnoDB と同様、完全なトランザクション機能を外部キー参照をサ ポートしていますが、やや時代送れになりつつあるようです。 SolidDB_ や Falcon_ といった `その他のストレージエンジン`_ まだまだ圏外の話です。現状では、おそらく InnoDB が最良の選択でしょう。 .. _storage_engines: http://dev.mysql.com/doc/refman/5.0/en/storage-engines.html .. _ストレージエンジン: storage_engines_ .. _MyISAM: http://dev.mysql.com/doc/refman/5.0/en/myisam-storage-engine.html .. _BDB: http://dev.mysql.com/doc/refman/5.0/en/bdb-storage-engine.html .. _InnoDB: http://dev.mysql.com/doc/refman/5.0/en/innodb.html .. _Other storage engines: http://dev.mysql.com/doc/refman/5.1/en/storage-engines-other.html .. _SolidDB: http://forge.mysql.com/projects/project.php?id=139 .. _Falcon: http://dev.mysql.com/doc/falcon/en/index.html .. _その他のストレージエンジン: `Other storage engines`_ MySQLdb ------- `MySQLdb`_ は Python から MySQL にアクセスするためのインタフェースです。 Django から利用できる MySQL の全ての機能を使うには、 バージョン 1.2.1p2 以 降が必要です。 .. note:: MySQLdb を Django から使おうとして ``ImportError: cannot import name ImmutableSet`` が出る場合は、おそらく MySQLdb に古い ``sets.py`` ファイルが入っていて、 Python 2.4 の同名の組 み込みモジュールと衝突しています。この問題を回避するには、 1.2.1p2 以降 の MySQLdb をインストールしてください。上書きインストールした場合には、 MySQLdb のインストールディレクトリを調べ、以前のバージョンの ``sets.py`` が入っていれば除去してください。 .. _MySQLdb: http://sourceforge.net/projects/mysql-python .. _Creating your database: データベースを作成する ---------------------- コマンドラインツールを使って、以下の SQL を発行すれば `データベースを作成`_ できます:: CREATE DATABASE CHARACTER SET utf8; これで、全てのテーブルとカラムがデフォルトで UTF-8 を使うようになります。 .. _create your database: http://dev.mysql.com/doc/refman/5.0/en/create-database.html .. _データベースを作成: `create your database`_ .. _mysql-collation: コレーションに関する設定 ~~~~~~~~~~~~~~~~~~~~~~~~~~~ カラムのコレーション設定は、データの保存方法や、文字列の等価性の定義を制御 しています。コレーションはデータベース全体でも、テーブル単位でも、カラム単 位でも設定できます。コレーションの詳細は MySQL のドキュメントで `詳しく解説されています `_ 。いずれの場合でも、コレー ションの設定は直接データベーステーブルに対して行ってください。 Django はモ デル定義でコレーションを設定する方法を提供していません。 .. _documented thoroughly: http://dev.mysql.com/doc/refman/5.0/en/charset.html デフォルトの構成では、 MySQL は UTF-8 のデータベースに対して ``utf8_general_ci_swedish`` コレーションを使います。この設定では、全ての文 字列の等値比較が *大小文字を区別* せず行われます。つまり、 ``"Fred"`` と ``"freD"`` はデータベースレベルでは同じ値だとみなされるのです。そのため、デ フォルトのコレーションを使っていると、フィールドに ``unique`` 制約をかけた ときに、 ``"aa"`` と ``"AA"`` は等しいとみなされ (一意性が破れるので) 同じ カラムに入れられなくなります。 大抵のケースでは、デフォルトの設定はさして問題を起こしません。しかし、特定 のカラムやテーブルで大小文字を区別させたいなら、そのカラムやテーブルに ``utf8_bin`` コレーションを指定せねばなりません。その場合、注意すべきなのは、 MySQLdb 1.2.2 を使っていると、 Django のデータベースバックエンドが、データ ベースから取り出した文字列フィールドの値として (unicode 文字列ではなく) bytestring を返すということです。このふるまいは、 *常に* unicode を返す、と いう Django の通常のやりかたから大きくかけ離れています。コレーションを ``utf8_bin`` にして、 bytestring を受け取ったときの扱いは、開発者に委ねられ ています。 Django 自体はこのカラムを問題なく扱えますが、一貫性をもってデー タを処理したければ、 ``django.utils.encoding.smart_unicode()`` を何度も 呼び出すことになるでしょう。(データベースバックエンドレイヤとモデルの操作レ イヤは内部的に分離しているため、変換が必要かどうかをデータベースレイヤでは 判断できないので) Django はこの変換に関知しないのです。 MySQLdb 1.2.1p2 を使っているなら、コレーションを ``utf8_bin`` にしても、 :class:`~django.db.models.CharField` は unicode 文字列を返します。しかし、 今度は :class:`~django.db.models.TextField` が (Python 標準モジュール ``array`` の) ``array.array`` を返します。データをデータベースから読み出す ときに、変換に必要な情報が手にはいらないので、 Django 側ではどうしようもあ りません。 この問題は `MySQLdb 1.2.2 で解決済み `_ なので、 ``itf8_bin`` コレーションで :class:`~django.db.models.TextField` を使いたけ れば、バージョンを 1.2.2 に上げて、バイト文字列として扱うよう勧めます (それ ほど難しくはありません)。 MySQLdb 1.2.1p2 で ``utf8_bin`` コレーションの設定されたテーブルを使うのな ら、 :class:`django.contrib.sessions.models.Session` のテーブル (通常は ``django_session``) や、 :class:`django.contrib.admin.models.LogEntry` のテーブル (通常は ``django_admin_log``) のコレーションに ``utf8_collation_ci_swedish`` (デフォルトのコレーション) を使わねばなりませ ん。これらは標準の Django のテーブルのうち、内部的に :class:`~django.db.model.TextField` を使っているものだからです。 .. _fixed in MySQLdb 1.2.2: http://sourceforge.net/tracker/index.php?func=detail&aid=1495765&group_id=22307&atid=374932 .. _Connecting to the database: データベースに接続する ---------------------- :ref:`設定に関するドキュメント ` を参照してください。 接続に関する設定は、以下の順に適用されます: 1. :setting:`DATABASE_OPTIONS` 2. :setting:`DATABASE_NAME`, :setting:`DATABASE_USER`, :setting:`DATABASE_PASSWORD`, :setting:`DATABASE_HOST`, :setting:`DATABASE_PORT` 3. MySQL のオプション設定ファイル 別の言い方をするなら、 :setting:`DATABASE_OPTIONS` 内にデータベースの名前を 設定すると、その内容は :setting:`DATABASE_NAME` よりも優先順位が高くなり、 さらに :setting:`DATABASE_NAME` は `MySQL のオプション設定ファイル`_ の内容 をオーバライドするということです。 MySQL のオプション設定ファイルを使う例を以下に示します:: # settings.py DATABASE_ENGINE = "mysql" DATABASE_OPTIONS = { 'read_default_file': '/path/to/my.cnf', } # my.cnf [client] database = DATABASE_NAME user = DATABASE_USER password = DATABASE_PASSWORD default-character-set = utf8 この他にも、MySQLdb の接続オプションには、 ``ssl``, ``use_unicode``, ``init_command``, ``sql_mode`` といった便利なものがあります。詳しくは `MySQLdb のドキュメント`_ を参照してください。 .. _MySQL option file: http://dev.mysql.com/doc/refman/5.0/en/option-files.html .. _MySQLdb documentation: http://mysql-python.sourceforge.net/ .. _`MySQL のオプション設定ファイル`: `MySQL option file`_ .. _`MySQLdb のドキュメント`: `MySQLdb documentation`_ .. _Creating your tables: テーブルを作成する ------------------ Django はスキーマを作成する際にストレージエンジンを指定しません。そのため、 テーブルは常にサーバに設定されたデフォルトのストレージエンジンで作成されま す。作成されるテーブルを特定のタイプにしたければ、データベースサーバのデフォ ルトストレージエンジンを Django で使いたいストレージエンジンに合わせるのが 一番簡単です。 ホスティングサービスを使っていて、サーバのデフォルトのストレージエンジンを 変更できない場合、二つの選択肢があります。 * テーブルが作成された後に、以下のようなクエリを発行して、ストレージ エンジンを (InnoDB) などに変更します:: ALTER TABLE ENGINE=INNODB; テーブルが沢山ある場合には、これは相当骨がおれることでしょう。 * あるいは、テーブルを作成する前に、 MySQLdb の ``init_command`` オプショ ンを使います:: DATABASE_OPTIONS = { ... "init_command": "SET storage_engine=INNODB", ... } このように設定しておくと、接続時にデフォルトのストレージエンジンが変更 されます。ただし、テーブルが全て作成され、運用環境で動き始めたら、この オプションを外しておかねばなりません。 * syncdb 時にストレージエンジンを変更するもう一つの方法は、 Wiki の `AlterModelOnSyncDB`_ に記載されています。 .. _AlterModelOnSyncDB: http://code.djangoproject.com/wiki/AlterModelOnSyncDB ``BooleanField`` に関する注意 ------------------------------- MySQL には直接的な ``BOOLEAN`` カラム型がないので、 Django は :class:`~django.db.models.BooleanField` の値を ``TINYINT`` カラムを使って 0 または 1 で保存します。詳しくはモデルフィールドのドキュメントを参照してくだ さい。ただし、フィールドの値を出力したり、値が ``True`` や ``False`` でなけ ればならないような場合を除いて、特に問題はありません。 .. _sqlite-notes: SQLite に関する注意 ===================== バージョン 3.3.5 以前の SQLite には、 ``ORDER_BY`` パラメタの扱いかたに `バグがあります `_ 。そのため、クエリセットメソッド ``extra()`` を使って ``select`` のパラメタを指定しようとすると問題を引き起 こします。このバグは、 ``OperationalError: ORDER BY terms must not be non-integer constants`` とい うメッセージを出力します。 SQLite のバージョンを 3.3.6 に上げ、 ``pysqlite2`` モジュールを更新すれば、問題を解決できます。 .. _contain a bug: http://www.sqlite.org/cvstrac/tktview?tn=1768 バージョン 3.3.6 は 2006 年の 4 月にリリースされており、現在手に入る各プラッ トフォームのほとんどのバイナリ配布物で、Python から ``pysqlite2`` や ``sqlite3`` を介して使える SQLite は新しいバージョンなので、あまり大きなイ ンパクトはありません。 ただし、 Windows の場合、 Python 2.5 の公式の安定版リリースのバイナリ配布物 には (今のところ 2.5.2 も)、 SQLite 3.3.4 が組み込まれているため、バグが確 認されています。このため (Django 1.0 で) 3 つのテストスイートが失敗します。 この問題は、上で述べたように、 新しいバージョン SQLite が組み込まれた ``pysqlite2`` (``pysqlite-2.x.x.win32-py2.5.exe``) をダウンロードしてインス トールすれば解決できます。 Python 2.6 には新たなバージョンの SQLite が付属 する予定なので、この問題の影響を受けないはずです。 上記のプラットフォームを使っていて、 ``pysqlite`` や SQLite を更新する必要 があるなら、Django のソースツリーの ``django/db/backends/sqlite3/base.py`` ファイルを手で編集して、 ``sqlite3`` より ``pysqlite2`` が先に import され るように変更してください。 .. _oracle-notes: .. _Oracle notes: Oracle に関する注意 ==================== Django はバージョン 9i 以降の `Oracle データベースサーバ`_ をサポートしてい ます。 Django の ``regex`` および ``iregex`` クエリオペレータを使うには、 バージョン 10g 以降の Oracle を使う必要があります。 バージョン 4.3.1 以降の `cx_Oracle`_ ドライバが必要です。 .. _`Oracle Database Server`: http://www.oracle.com/ .. _`cx_Oracle`: http://cx-oracle.sourceforge.net/ .. _`Oracle データベースサーバ`: `Oracle Database Server`_ Oracle で ``python manage.py syncdb`` コマンドを動かすには、データベースユー ザに以下のコマンドを実行できる権限が必要です: * CREATE TABLE * CREATE SEQUENCE * CREATE PROCEDURE * CREATE TRIGGER Django のテストスイートを実行させるには、 *さらに* 以下の権限が必要です: * CREATE USER * DROP USER * CREATE TABLESPACE * DROP TABLESPACE .. _Connecting to the Oracle database: データベースへの接続 -------------------------- Oracle を使う場合、 Django の settings.py は以下のように設定します:: DATABASE_ENGINE = 'oracle' DATABASE_NAME = 'xe' DATABASE_USER = 'a_user' DATABASE_PASSWORD = 'a_password' DATABASE_HOST = '' DATABASE_PORT = '' ``tnsnames.ora`` ファイルや、 SID として扱われる名前 (上の例では "xe") を使わない場合は、以下のように :setting:`DATABASE_HOST` および :setting:`DATABASE_PORT` を設定してください:: DATABASE_ENGINE = 'oracle' DATABASE_NAME = 'xe' DATABASE_USER = 'a_user' DATABASE_PASSWORD = 'a_password' DATABASE_HOST = 'dbprod01ned.mycompany.com' DATABASE_PORT = '1540' :setting:`DATABASE_HOST` と :setting:`DATABASE_PORT` は、両方とも指定するか、 両方とも空にするかどちらかにしてください。 .. _Tablespace options: テーブルスペース ------------------ Oracle ベースのシステムでパフォーマンス向上に使われているパラダイムとして、 「 `テーブルスペース`_ (tablespace)」によるディスクレイアウトの構築がありま す。 ``db_tablespace`` オプションを ``Meta`` と ``Field`` クラスに追加する と、 Oracle バックエンドはテーブルスペースを利用します (バックエンドがテー ブルスペースをサポートしなければ、 Django はこのオプションを無視します)。 .. _`tablespaces`: http://en.wikipedia.org/wiki/Tablespace .. _`テーブルスペース`: `tablespaces`_ モデルのテーブルにテーブルスペースを指定するには、モデルの内部クラス ``Meta`` に ``db_tablespace`` オプションを指定します。モデル全体とは別のテー ブルスペースをフィールドのカラムインデクスに指定したければ、フィールドのコ ンストラクタに ``db_tablespace`` を指定します。カラムごとにインデクスを生成 しない場合には、 ``db_tablespace`` オプションは無視されます:: class TablespaceExample(models.Model): name = models.CharField(max_length=30, db_index=True, db_tablespace="indexes") data = models.CharField(max_length=255, db_index=True) edges = models.ManyToManyField(to="self", db_tablespace="indexes") class Meta: db_tablespace = "tables" 上の例では、 ``TablespaceExample`` モデルの生成するテーブル (モデルテーブルと多対多のリレーションのテーブル) は、 ``tables`` という名前 のテーブルスペースに保存されます。 ``name`` フィールドと、多対多リレーショ ンテーブルのインデクスは ``indexes`` テーブルスペースに保存されます。 ``data`` フィールドもインデクスを生成しますが、このインデクスのテーブルスペー スは指定されていないので、デフォルトの挙動としてテーブルスペース ``tables`` に保存されます。 .. versionadded:: 1.0 ``db_tablespace`` オプションのデフォルト値を指定するには、 :setting:`DEFAULT_TABLESPACE` および :setting:`DEFAULT_INDEX_TABLESPACE` 設 定を使います。これらの設定は、組み込みの Django アプリケーションや、ソース コードをいじれないアプリケーションに対してテーブルスペースを指定する場合に 便利です。 Django 自体にはテーブルスペースを作成する機能はありません。 テーブルスペースの作成や管理の方法は、 `Oracle のドキュメント`_ を参照して ください。 .. _`Oracle's documentation`: http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/statements_7003.htm#SQLRF01403 .. _`Oracle のドキュメント`: `Oracle's documentation`_ .. _Naming issues: 名前に関する制約 ----------------- Oracle は名前の長さを 30 文字以下に制限しています。この制限に合わせるために、 バックエンドは識別子名を切り詰めて、最後の 4 文字を MD5 のハッシュ値で置き 換えます。 .. _NULL and empty strings: NULL 値よび空文字列 ---------------------- Django は通常、 NULL ではなく空文字列を使うようにしていますが、 Oracle はこ れらを別々のものとして扱います。この問題を回避するには、 Oracle バックエン ドは空文字列を値として受け入れるフィールドに ``null=Ture`` オプションを 強制的に付加します。データベースから値を取り出すとき、フィールドの値が NULL であれば、そのフィールドの値は実際には空文字列であるとみなし、値も暗黙のう ちに空文字列に変換されます。 .. _TextField limitations: ``TextField`` への制限 ------------------------- Oracle バックエンドは ``TextField`` を ``NCLOB`` カラム形式で保存します。 Oracle は、一般に LOB カラムに以下の制約を課しています: * LOB カラムは主キーにできません。 * LOB カラムはインデクス化に使えません。 * LOB カラムは ``SELECT DISTINCT`` できません。従って、Oralce バックエン ドを使っていて、 ``TextField`` カラムを含むモデルに対して ``QuerySet.distinct`` を行うとエラーを引き起こします。このエラーを避け るには、 ``distinct()`` クエリの対象モデルから ``TextField`` を除去し、 ``TextField`` を持つ他のモデルを定義しておいてリレーションを張ってくだ さい。