モデルとは、サイトを構成するデータの、ただ一つかつ最終的なデータソースを指
します。モデルには、保存したいデータに不可欠なデータフィールドと、その振舞
いが収められています。一般的に、各モデルは単一のデータベーステーブルに対応
づけられています。
簡単な例
以下のモデル例では、 first_name および last_name というフィールドを
持った Person を定義しています:
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
first_name と last_name はモデルの フィールド (fields) です。各
フィールドはクラス属性として定義され、各属性がデータベースのカラムに対応し
ます。
上の Person モデルは、以下のようなデータベーステーブルを生成します:
CREATE TABLE myapp_person (
"id" serial NOT NULL PRIMARY KEY,
"first_name" varchar(30) NOT NULL,
"last_name" varchar(30) NOT NULL
);
以下に技術的な注意点を示します:
- テーブルの名前、 myapp_person はモデルのメタデータから自動的に導
出したものですが、オーバライドもできます。後述の テーブル名 を参照
してください。
- id は自動的に追加されますが、この挙動もまたオーバライドできます。
自動的な主キーフィールド を参照してください。
- この例の CREATE TABLE SQL 文は PostgreSQL の書式で書かれています
が、 Django は 設定ファイル に指定されたデータベースバックエンド向
けの SQL を使います。
フィールド
モデルで最も重要であり、かつモデル定義で最小限必要な部分は、モデル内が定義
しているデータベースフィールドのリストです。フィールドはクラスの属性として
定義されています。
例を示します:
class Musician(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
class Album(models.Model):
artist = models.ForeignKey(Musician)
name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField()
フィールド名の制約
Django がモデルのフィールド名に課している制約は二つしかありません:
フィールド名は Python の予約語であってはなりません。さもなければ
Python のシンタクスエラーを引き起こすからです。例えば:
class Example(models.Model):
pass = models.IntegerField() # 'pass' は予約語です!
フィールド名には二つ以上の連続するアンダースコアを入れてはなりません。
なぜなら、Django のクエリ照合構文で使われているからです。例えば:
class Example(models.Model):
foo__bar = models.IntegerField() # 'foo__bar' に '__' が入っています!
フィールドの名前は必ずしもデータベースのカラム名と一致していなくてもよいの
で、これらの制約は回避可能です。詳しくは後述の db_column を参照してくだ
さい。
join や where, select のような SQL の予約語は、モデルのフィール
ド名に使っても かまいません 。というのも、Django はいかなる SQL クエリ文
でも全てのデータベーステーブル名やカラム名をエスケープするからです。エスケー
プにはデータベースエンジン固有のクオートシンタクスを使います。
フィールドのタイプ
モデルの各フィールドは適切な Field クラスのインスタンスにせねばなりませ
ん。 Django はフィールドクラス型を以下のいくつかの判定に使います:
- データベースのカラム型 (INTEGER, VARCHAR など)。
- Django の admin サイトで使うウィジェットの選択
(<input type="text">, <select> など)。
- Django の admin やマニピュレータで使われている最小限の検証
(validation)。
使えるフィールド型は以下の通りです。
AutoField
IntegerField の一種で、利用可能な ID の中から自動的にインクリメントして
いきます。通常、このフィールドが直接必要になることはないでしょう。主キーの
フィールドは、特に指定しない限り自動的に追加されます。
自動的な主キーフィールド を参照してください。
BooleanField
真偽 (true/false) 値を表すフィールドです。
admin ではこのフィールドはチェックボックスとして表現されます。
CharField
文字列フィールドで、短い文字列からやや長いものに適しています。
大量のテキストを入れたい場合には TextField を使って下さい。
admin では <input type="text"> (一行の入力フィールド) で表現されます。
CharField には max_length という必須の引数があります。この引数はフィー
ルドの (文字数で表した) 最大長です。 max_length への制約はデータベースと
Django 内の検証の両方のレベルで行われます。
ベテラン Django ユーザへの注意: Django 内での一貫性を持たせるため、
引数名 maxlength は max_length に変わりました。これまで通り
maxlength 引数は使えますが、今後は max_length を使うよう勧めます。
CommaSeparatedIntegerField
カンマで区切った整数からなるフィールドです。 CharField と同じく、
max_length 引数が必要です。
DateField
日付フィールドです。オプションの引数がいくつかあります:
| 引数 |
説明 |
| auto_now |
オブジェクトを保存する度に、その時の時刻を自動的に設
定します。 "last-modified" タイムスタンプの実現に便
利です。この値はオーバライドできるデフォルト値ではな
く、 常に 現在の日付になるので注意してください。 |
| auto_now_add |
オブジェクトを生成した時の時刻を自動的に設定します。
タイムスタンプの生成に便利です。この値はオーバライド
できるデフォルト値ではなく、 常に 現在の日付になる
ので注意してください。 |
admin では、 JavaScript のカレンダーと 「今日」へのショートカットのついた
<input type="text"> として表現されます。 JavaScript カレンダーは常に
日曜日から週が始まります。
DateTimeField
日付と時刻のフィールドです。 DateField と同じオプションを取ります。
admin では JavaScript のショートカットのついた <input type="text">
フィールドで表現されます。
DecimalField
開発版の Django で新たに追加された機能です
固定精度の 10 進小数です。 Python の Decimal 型インスタンスとして表現さ
れます。 必須の 引数が 2 つあります:
| 引数 |
説明 |
| max_digits |
値を表現するのに使える最大桁数です。 |
| decimal_places |
小数部の保存に使われる桁数です。 |
例えば、小数部が 2 桁で、 999 までの数を表現できるようなフィールドを作成す
るには、以下のようにします:
models.DecimalField(..., max_digits=5, decimal_places=2)
小数部の精度が 10 桁で、 10 億までの数を表現できるようにしたければ、以下の
ようにします:
models.DecimalField(..., max_digits=19, decimal_places=10)
admin では、 <input type="text"> (一行のテキスト入力) で表現されます。
EmailField
値が有効な e-mail アドレスであるかチェックする CharField です。
Django 0.96 では、 max_length を指定できません。 max_length は自動的に
75 にセットされるからです。 開発版の Django では、 max_length はデフォルト
で 75 にセットされますが、デフォルト値を書き換えるよう指定することができます。
FileField
ファイルアップロードのためのフィールドです。 必須の 引数を一つ持ちます:
| 引数 |
説明 |
| upload_to |
ローカルのファイルシステム上のパスです。
このパスは MEDIA_ROOT に設定したパスの後ろに
つけられ、 get_<fieldname>_url() ヘルパ関数
の出力を決める際に使われます。 |
パスには strftime によるフォーマット を入れてもかまいません、フォーマッ
ト文字列が入っていれば、(ディレクトリが同名のアップロードファイルで埋まらな
いように)ファイルのアップロード日時に置き換わります。
admin では、 <input type="file"> (ファイルアップロードウィジェット)
で表現されます。
モデル中で FileField や ImageField (下記参照) を使うには、以下のよう
なステップが必要です:
- Django にアップロードされたファイルを保存させたい場所のフルパス
を設定ファイル中の MEDIA_ROOT に指定します。(パフォーマンス
上の理由から、アップロードされたファイルはデータベースに保存され
ません。) 保存場所への公開 URL を MEDIA_URL に指定します。
ディレクトリは Web サーバのユーザアカウントによって書き込み可能
であるか確認してください。
- FileField や ImageField をモデルに定義します。このとき、
upload_to オプションを指定して、 MEDIA_ROOT 下のサブディ
レクトリのどこにアップロードされたファイルを置くべきかを Django
に教えます。
- データベースに保存されるのはファイルへのパス (MEDIA_ROOT か
らの相対) です。Django の提供している get_<fieldname>_url 関
数を使うことになるでしょう。例えば、 mug_shot という名前の
ImageField があれば、画像への絶対 URL は
{{ object.get_mug_shot_url }} で取得できます。
例えば、 MEDIA_ROOT を '/home/media' にして、 upload_to を
'photos/%Y/%m/%d' に設定したとします。 upload_to の '%Y/%m/%d'
の部分は strftime と同じフォーマット文字を使っています。すなわち、 '%Y'
が 4 桁の年号、 '%m' が 2 桁の月、 '%d' が 2 桁の日を表します。
従って、ファイルを 2007 年の 1 月 15 日にアップロードすると、
/home/media/photos/2007/01/15 に保存されることになります。
アップロードファイルのディスク上でのファイル名を取得したい場合や、ファイル
にアクセスするための URL を調べたい場合、ファイルのサイズを知りたい場合は、
それぞれ get_FOO_filename(), get_FOO_url(), get_FOO_size()
メソッドを使えます。詳しくは get_FOO_ メソッド の説明を参照してください。
ファイルのアップロードを処理するときには、常にアップロード先の場所やアップ
ロードされるファイルに注意して、セキュリティホールを避けるようにしてくださ
い。 アップロードされる全てのファイルをチェックして 、予想外のファイルが
アップロードされないようにしましょう。例えば、バリデーションを行わずに Web
サーバのドキュメントルート下へのファイルのアップロードを盲目的に受け入れる
と、そこに誰かが CGI や PHP スクリプトをアップロードして、あなたのサイト上
の URL を訪問した人にスクリプトを実行させられてしまいます。そんなことを許し
てはなりません。
開発版の機能です: デフォルトでは、 FileField インスタンスは
varchar(100) カラムをデータベースに作成します。他のフィールドにしたければ、
max_length 引数を使って最大長を変更することができます。
FilePathField
ファイルシステム上のあるディレクトリ下のファイル名だけを選べるようになって
いるフィールドです。 3 つの特別な引数があり、そのうち最初の一つは 必須
です:
| 引数 |
説明 |
| path |
必須です。 FilePathField が選択肢を作成するための
ディレクトリへの絶対パスです。例: "/home/images" |
| match |
オプションです。正規表現を表す文字列で、
FilePathField がファイル名のフィルタに使います。正
規表現はフルパスではなくファイル名に適用されるので注意
してください。 例: "foo.*\.txt$" は foo23.txt
にはマッチしますが、 bar.txt や foo23.gif には
マッチしません。 |
| recursive |
オプションです。 True または False です。デフォ
ルトは False で、 path のサブディレクトリを含め
るかどうかを指定します。 |
もちろん、これらの引数を組み合わせて使ってもかまいません。
よくある勘違いは、 match がファイル名ではなくフルパスに適用されると思っ
てしまうことです。以下の例:
FilePathField(path="/home/images", match="foo.*", recursive=True)
は /home/images/foo.gif にはマッチしますが、ファイル名本体 (foo.gif
や bar.gif) にマッチするため、 /home/images/foo/bar.gif にはマッチ
しません。
開発版の機能です: デフォルトでは、 FilePathField インスタンスは
varchar(100) カラムをデータベースに作成します。他のフィールドにしたければ、
max_length 引数を使って最大長を変更することができます。
FloatField
開発版の Django で仕様が変更されました。
浮動小数点数です。Python の float 型インスタンスで表現されます。
admin では、 <input type="text"> (一行の入力フィールド) で表現されます。
NOTE: 開発版の Django では、 FloatField の仕様が変更されています。
以前の仕様は、 Django 0.96 のドキュメント を参照してください。
ImageField
FileField に似ていますが、アップロードされたオブジェクトが有効なイメー
ジかどうか検証します。二つのオプション引数、 height_field および
width_field をとり、これらの値が設定されている場合には、モデルのインス
タンスを保存するときに画像の高さと幅も同時に保存します。
ファイルフィールドで使える get_FOO_* メソッドの他に、 ImageField で
は get_FOO_height() および get_FOO_width() メソッドを使えます。詳し
くは get_FOO_height() と get_foo_width() の説明 を参照してください。
Python Imaging Library が必要です。
開発版の機能です: デフォルトでは、 ImageField インスタンスは
varchar(100) カラムをデータベースに作成します。他のフィールドにしたければ、
max_length 引数を使って最大長を変更することができます。
IntegerField
整数です。
admin では、 <input type="text"> (一行の入力フィールド) で表現されます。
IPAddressField
IP アドレスを 文字列形式で表したもの (例: "192.0.2.30") です。
admin では、 <input type="text"> (一行の入力フィールド) で表現されます。
NullBooleanField
BooleanField と, 同じですが、 NULL を選択肢に使えます。
null=True の BooleanField の代わりに使って下さい。
admin では、「不明」 ("Unknown") 「はい」 ("Yes")、「いいえ」 ("No") の選択
肢をもつ <select> ボックスで表現されます。
PhoneNumberField
CharField と同じですが、値がアメリカ形式の電話番号として有効な形式
(XXX-XXX-XXXX) かどうかをチェックします。
PositiveIntegerField
IntegerField と同じですが、正の数でなければなりません。
PositiveSmallIntegerField
PositiveIntegerField と同じですが、ある範囲以下 (データベース依存です)
の値しか使えません。
SlugField
「スラグ (slug)」は新聞業界の用語で、内容を示す短いラベルです。スラグは文字、
数字、アンダースコア、ハイフンだけからなります。スラグはよく URL に使
われます。
CharField と同様、 max_length を指定できます。指定しなかった場合、
Django はデフォルト値の 50 を使います。 db_index=True になります。
SmallIntegerField
IntegerField と同様ですが、ある範囲以下 (データベース依存です) の値しか
使えません。
TextField
長いテキストのためのフィールドです。
admin では、 <textarea> (複数行の入力フィールド) で表現されます。
TimeField
時刻です。 DateField や DateTimeField と同じく、自動的に値を埋めるた
めのオプションを使えます。
admin では、JavaScript のショートカットがついた <input type="text"> で
表現されます。
URLField
URL を表すフィールドです。 verify_exists オプションを True (デフォ
ルト値です) にすると、指定された URL が実在する (URL は実際にロードでき、か
つ 404 応答を返さない) かどうか検証します。
admin では、 <input type="text"> (一行の入力フィールド) で表現されます。
URLField にはオプションの引数として、フィールドの最大長 (文字数) を表す
max_length を指定できます。 max_length はデータベースのレベルや
Django のバリデーションで自動的に指定されます。 max_length を指定しない
ときのデフォルトの値は 200 です。
USStateField
2 文字のアメリカ合衆国州名略号です。
admin では、 <input type="text"> (一行の入力フィールド) で表現されます。
XMLField
TextField と同様ですが、指定されたスキーマに従って、値が有効な XML であ
るか検証します。 schema_path を必須の引数にとります。 schema_path
は検証に使う RelaxNG スキーマを指すファイルシステム上のパス名です。
フィールドのオプション
全てのフィールド型で、以下の引数を指定できます。これらの引数はすべてオプショ
ンです。
null
True にすると、 Django は空の値を NULL としてデータベースに入れます。
デフォルト値は False です。
空の文字列値は NULL ではなく空文字列として保存されることに注意して下さ
い。 null=True が使えるのは、整数型やブール型、日付のような、文字列では
ないフィールド型の場合だけです。 null はデータベースでの記録操作にのみ
かかわるパラメタなので、フォーム上で空の値を入力できるようにしたければ
blank=True も指定する必要があるでしょう (blank については後で述べます)。
特別な理由のない限り、 CharField や TextField のような、文字列ベース
のフィールドには null を指定しないようにしてください。文字列ベースのフィー
ルドが nill=True であるということは、「データがない」ことを表すのに
NULL と空文字列という二つの値が存在することを示します。多くの場合、「デー
タがない」ことを表すのに二つのを取り得るのは冗長でしかありません。 Django
の慣習では、データのない文字列フィールドの値は NULL ではなく空文字列で
す。
Note
Oracle バックエンドを使っている場合、データベースの制約のため、
空文字列を許すような文字列ベースのフィールドは、 null=True オプション
が強制的に付加され、 NULL が空の文字列を指すようになります。
blank
True にすると、フィールドの値を空白 (blank) にできます。デフォルト値は
True です。
null とは違うことに注意してください。 null が純粋にデータベース上の
表現に関わる概念であるのに対し、 blank とは値の検証 (validation) に関わ
る概念です。あるフィールドに blank=True を指定すると、 Django の admin
サイト上で、空の値のエントリを作れるようになります。 blank=False にする
と、そのフィールドには必ず値を入れねばなりません。
choices
2 要素のタプルからなる iterable (リストまたはタプル) を、フィールドの値の選
択肢にします。
この値を指定すると、 Django の admin には標準的なテキストフィールドの代わり
に選択ボックスが表示され、指定された選択肢だけをえらべるようになります。
選択肢リストは以下のようになります:
YEAR_IN_SCHOOL_CHOICES = (
('FR', 'Freshman'),
('SO', 'Sophomore'),
('JR', 'Junior'),
('SR', 'Senior'),
('GR', 'Graduate'),
)
各タプルの最初の要素は、データベースに実際に保存される値です。二つ目の値は
各オプションに対する人間可読な名前です。
選択肢リストは、モデルクラスの一部として定義できます:
class Foo(models.Model):
GENDER_CHOICES = (
('M', 'Male'),
('F', 'Female'),
)
gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
また、モデルクラスの外でも定義できます:
GENDER_CHOICES = (
('M', 'Male'),
('F', 'Female'),
)
class Foo(models.Model):
gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
また、選択肢をグループごとに集めて、名前をつけられます:
MEDIA_CHOICES = (
('Audio', (
('vinyl', 'Vinyl'),
('cd', 'CD'),
)
),
('Video', (
('vhs', 'VHS Tape'),
('dvd', 'DVD'),
)
),
('unknown', 'Unknown'),
)
各タプルの最初の要素は、選択肢グループの名前です。二つ目の要素は、2 要素の
タプルからなるイテレーション可能なオブジェクトです。各 2 要素タプルには、
選択肢の値と、人間可読な名前を指定します。(上の例の unknown オプション
のように) グループ化されたオプションとされていないオプションを混ぜても構い
ません。
choices セットを持つモデルフィールド各々について、 Django は特殊なメソッ
ドを追加し、フィールドの現在値を人間可読な形式で取得できるようにします。デー
タベース API ドキュメントの get_FOO_display を参照してください。
最後に、 choices はリストやタプルでなくてもよく、任意の iterable オブジェク
トでかまわないことに注意してください。つまり、 choices は動的生成できるので
す。とはいえ、 choices を動的生成するようなハックをするくらいなら、適当
なデータベーステーブルを ForeignKey で参照した方がよいでしょう。
というのも、 choices はあまり変更のない静的な選択肢のためのオプションだ
からです。
core
オブジェクトが他のオブジェクトからリレーションを張られていて、インライン編
集の対象であるときに、フィールドをコアデータとしてマークします。
Django の admin 上でインライン編集しているオブジェクトの "core" フィールド
の値を全て消去すると、そのオブジェクトは削除されます。
インライン編集可能なリレーションには、 core=True であるフィールドが少な
くとも一つ必要です。なければエラーになります。
"core" を指定したフィールドは、Django admin サイト上では必須のフィールドと
して扱われるので注意してください。実質的には、インライン編集の対象になるよ
うなオブジェクトの全てのフィールドに core=True を指定しておかねばなり
ません。
db_column
フィールドに使うデータベースカラム名です。この値を指定しなければ、 Django
はフィールド名を使います。
データベースカラム名が SQL の予約語であったり、 Python で変数名として使えな
い文字を含んでいる (よくあるのはハイフンです) 場合でも問題ありません。
Django は必要に応じてカラム名やテーブル名をクオートします。
db_index
True にすると django-admin.py sqlindexes を実行した時に、フィールド
に対して CREATE INDEX 文を出力します。
db_tablespace
開発版の Django で新たに追加された機能です
このフィールドをインデクス化する際に、データベースのテーブルスペース上での
フィールドのインデクスの名前に使います。デフォルトの値は、プロジェクトで
設定されている DEFAULT_INDEX_TABLESPACE です。この値がなければ、
モデルの db_tablespace を使います。テーブルスペースをサポートしていない
バックエンドでは、このオプションは無視されます。
default
フィールドのデフォルト値です。この値は、何らかの値でも、呼び出し可能オブジェ
クトでもかまいません。呼び出し可能オブジェクトの場合、新たなオブジェクトが
生成されるたびに呼び出されます。
editable
False にすると、 admin 上や、オブジェクトの AddManipulator および
ChangeManipulator クラスを使ったフォーム処理でフィールドの値を編集でき
なくなります。デフォルト値は True です。
help_text
オブジェクトの admin フォームの下に表示される、追加の「ヘルプ」テキストです。
とはいえ、オブジェクトが admin のフォームを持っていなくてもドキュメントとし
て有用でしょう。
この値は admin インタフェース上に表示されるときに HTML エスケープされ
ない ので注意してください。必要ならば、下記の例のように help_text に
HTML を含めてもかまいません:
help_text="<em>YYYY-MM-DD</em> の形式で記入してください。"
primary_key
True に指定すると、フィールドをモデルの主キーにします。
モデルのどのフィールドにも primary_key=True を指定しなければ、Django は
自動的に以下のフィールドを追加します:
id = models.AutoField('ID', primary_key=True)
従って、デフォルトの主キーの振舞いを変更したいのでないかぎり、
primary_key=True をフィールドに指定しておく必要はありません。
primary_key=True であるということは、 null=False 、 かつ
unique=True であることを指します。一つのオブジェクトには一つしか主キー
を指定できません。
radio_admin
デフォルトでは、 ForeignKey のフィールドや choices の設定されたフィー
ルドに対して、 Django の admin は選択ボックスインタフェース (<select>) を使
います。 radio_admin を True にすると、 Django はラジオボタンのイン
タフェースを使います。
フィールドが ForeignKey であるか、 choices が設定されている
のでなければ、このオプションを指定してはなりません。
unique
True であれば、フィールドはテーブル全体で一意の値を取らねばなりません。
この制約は、データベースレベルと Django の admin のレベルで適用されます。
重複した値を持つ unique フィールドを含んだモデルを保存しようとすると、
モデルの save() メソッドによって django.db.IntegrityError が送出さ
れます。
unique_for_date
DateField や DateTimeField 型のフィールドの名前を指定しておくと、そ
のフィールドの日付に対して一意な値になるように制約します。
例えば、 title という名前のフィールドがあり、
unique_for_date="pub_date" が指定されていたとすると、 Django は同じ
title や pub_date の値を持つようなエントリを受け入れません。
この制約は Django の admin フォームのレベルで適用され、データベースレベルで
は適用されません。
unique_for_month
unique_for_date と同様ですが、フィールドの値が月ごとに一意であるように
制約します。
unique_for_year
unique_for_date や unique_for_month と同様です。
validator_list
フィールドに適用する追加のバリデータ (検証機構) のリストです。各バリデータ
は呼び出し可能オブジェクトで、引数に field_data, all_data を取り、エラー
が生じたときには django.core.validators.ValidationError を送出するよう
になっていなければなりません (バリデータのドキュメント) を参照してくださ
い。
Django にはほんの少しだけバリデータがついてきます。バリデータは
django.core.validators に収められています。
詳細なフィールド名
各フィールドの型は、 ForeignKey, ManyToManyField および
OneToOneField を除き、オプションの固定引数 (positional argument) を第一
引数として指定できます。この引数には人間可読なカラム名を指定します。引数を
指定しなければ、 Django はカラム名のアンダースコアをスペースに変換して、自
動的に人間可読なカラム名を生成します。
下の例では、人間可読なカラム名は "Person's first name" になります:
first_name = models.CharField("Person's first name", max_length=30)
下の例では "first name" です:
first_name = models.CharField(max_length=30)
ForeignKey, ManyToManyField および OneToOneField では、第一引数
は必須で、モデルのクラスにします。従って、人間可読なカラム名を指定するには、
verbose_name キーワード引数を使います:
poll = models.ForeignKey(Poll, verbose_name="the related poll")
sites = models.ManyToManyField(Site, verbose_name="list of sites")
place = models.OneToOneField(Place, verbose_name="related place")
慣習的に、 verbose_name の先頭の文字は大文字にしないことになっています。
Django は必要なときに先頭の文字を自動的に大文字にします。
リレーション
関係データベースの威力はテーブルを相互に関連づけることにあるのはいうまでも
ありません。Django ではよく使われるデータベースリレーション (relationship)、
多対一 (many-to-one)、多対多 (many-to-many)、一対一 (one-to-one) を定義する
方法を提供しています。
多対一のリレーション
多対一のリレーションを定義するには ForeignKey を使います。このフィール
ドは他のフィールド型と同じように、モデルのクラス属性に含めて使えます。
ForeignKey には、固定引数が一つあり、リレーションを張る対象のクラスを
指定します。
例えば、 Car モデルに Manufacturer というフィールドを持たせたいとし
ましょう。すなわち、ある Manufacturer には複数の Car が対応するが、
各 Car には一つだけ Manufacturer が対応するようにしたいとしましょう。
この場合、以下のように定義します:
class Manufacturer(models.Model):
# ...
class Car(models.Model):
manufacturer = models.ForeignKey(Manufacturer)
# ...
再帰的なリレーションを張る、つまり自分自身への多対一のリレーションを張る場
合には、 models.ForeignKey('self') を使います。
未定義のモデルへのリレーションを作成した場合、モデルオブジェクトではなくモ
デルの名前も使えます:
class Car(models.Model):
manufacturer = models.ForeignKey('Manufacturer')
# ...
class Manufacturer(models.Model):
# ...
開発版の Django で新たに追加された機能: 他のアプリケーションで定義され
ているモデルを参照したければ、アプリケーションラベルを明示的に指定せねばな
りません。例えば、上の例の Manufacturer モデルが、 production とい
う別のアプリケーションで定義されているのなら、以下のように書かねばなりませ
ん:
class Car(models.Model):
manufacturer = models.ForeignKey('production.Manufacturer')
舞台裏では、 Django はフィールド名に "_id" をつけた名前でデータベースのカラ
ム名を生成します。上の例では、 Car モデルのデータベーステーブルには
manufacturer_id カラムが入ります (このカラム名は db_column を明示的
に指定して変更できます。詳しくは db_column を参照してください) 。とはい
え、カスタムのSQL 文を発行するのでないかぎり、データベースのカラム名をコー
ドで直接扱う必要はありません。
必須ではありませんが、 ForeignKey の名前 (上の例では manufacturer)
は、モデル名を小文字にしたものにするよう勧めます。もちろん好きな名前を付け
てもかまいません。例えば:
class Car(models.Model):
company_that_makes_it = models.ForeignKey(Manufacturer)
# ...
完全な使用例は 多対一のリレーションを持つモデルの例 を参照してください。
ForeignKey フィールドはリレーションの動作を定義するための引数をいくつか
とれます。これらは全てオプションです:
| 引数 |
説明 |
| edit_inline |
True にすると、リレーション先のオブジェクト
をリレーション元のオブジェクトのページで「イン
ラインで」編集できます。これにより、リレーショ
ン先のオブジェクトは独自の admin インタフェース
を持たなくなります。
models.TABULAR または models.STACKED を指
定してください。それぞれ、インライン編集可能な
オブジェクトをテーブルまたはスタックしたフィー
ルドとして表示します。 |
| limit_choices_to |
admin で利用可能な選択肢を制限するための、ラベ
ルと値を対応づけた辞書です
(データベース API のリファレンス 参照)。
Python の datetime モジュールと組み合わせて、
オブジェクトを日付で制限できます。例えば:
limit_choices_to = {
'pub_date__lte': datetime.now}
のようにすると、 pub_date が現在の日時より
前のオブジェクトしか選べなくなります。
より複雑なクエリを実現するために、辞書の代りに
Q オブジェクト (get_sql() メソッドを備
えたオブジェクト) も指定できます。
edit_inline と互換性がありません。
|
| max_num_in_admin |
インライン編集オブジェクトを編集するときに、
リレーションの張られたオブジェクトを admin に
最大何個まで表示するかを指定します。例えば、
ピザに乗せられるトッピングを 10 個までに制限
したければ、 max_num_in_admin=10 とする
ことで、ユーザに 10 個以上のトッピングを
入力させなくできます。
この制限では、リレーションの張られたオブジェク
トを実際に 10 個以上生成できなくするわけでは
ないので注意してください。この引数が制御して
いるのは admin インタフェースだけで、 Python
API レベルやデータベースレベルでは制限を課しま
せん。
|
| min_num_in_admin |
リレーションの張られたオブジェクトを admin
に少なくとも何個表示するかを指定します。
通常、オブジェクトの生成ステージ (creation stage)
では、 num_in_admin 個のインラインオブジェ
クトが表示され、編集ステージ (edit stage) では
既存のオブジェクトに加えて
num_extra_on_change 個の空白オブジェクトを
表示するようになっています。
ただし、リレーションの張られたオブジェクトの数
が min_num_in_admin 個以下の場合には表示
しません。 |
| num_extra_on_change |
オブジェクトの変更ステージにおいて、追加のブラ
ンクのフィールドを何個表示するかを指定します。 |
| num_in_admin |
オブジェクトの追加ステージで、インラインオブジェ
クトをデフォルトで何個表示するかを指定します。 |
| raw_id_admin |
ドロップダウンメニューの代わりに、整数を入力す
るフィールドだけを表示します。
関連づけの対象になるオブジェクトの数が多すぎて
選択ボックスが実用的でない場合に便利です。
edit_inline とは組み合わせて使えません。
|
| related_name |
リレーション先のオブジェクトから逆参照するとき
に使われる名前です。詳しくは
オブジェクトのリレーションに関する解説
を参照してください。
抽象ベースクラス を使っているなら、 補足
の related_name に関する説明にも目を通して
ください。
|
| to_field |
リレーション先のオブジェクトの、リレーションを
張る対象のフィールド名です。デフォルトでは、
リレーション先のオブジェクトの主キーを使います。 |
多対多のリレーション
多対多の (many-to-many) リレーションを定義するには ManyToManyField
を使います。このフィールドは他のフィールド型と同じように、モデルのクラス属
性に含めて使えます。
ManyToManyField には固定引数が一つあり、リレーションを張る対象のクラスを
指定します。
例えば、 Pizza には複数の Topping オブジェクトを持たせられます。
すなわち、ある Topping は複数のピザの上に置けて、逆にそれぞれのピザには
複数のトッピングを置けるというわけです。このリレーションを表すには次のように
します:
class Topping(models.Model):
# ...
class Pizza(models.Model):
# ...
toppings = models.ManyToManyField(Topping)
ForeignKey と同じく、モデル名ではなく文字列 'self' を使えば自分自身
へのリレーションを定義できます。また、モデル名の入った文字列を使えば、未定
義のモデルも参照できます。ただし、文字列を使ってモデルを参照できるのは、同
じ models.py ファイル中にあるモデルだけです。別のアプリケーション中のモデル
や、その他の場所から import したモデルは文字列で参照できません。
必須ではありませんが、 ManyToManyField の名前 (上の例では toppings)
は、リレーション先のモデル名の複数形にするよう勧めます。
背後では、 Django は中間の join テーブルを生成して、多対多のリレーション
を表現します。
どちらのモデルで ManyToManyField を定義してもかまいませんが、
どちらか片方のモデルにしか必要ありません -- 両方には指定できません。
一般的に、 Django の admin を使っている場合、 ManyToManyField インスタ
ンスを入れておくのは、 admin インタフェースで編集される側のオブジェクトにし
ておきます。上の例では、 topping は (Topping に ManyToManyField
の pizzas をもたせるのではなく) Pizza に入れておきます。というのも、
「トッピングを乗せるピザ」と考えるよりも「ピザの上に乗せるトッピング」を考
える方が自然だからです。こうして上の例では、 Pizza の admin フォームで
ユーザにトッピングを選ばせることになります。
完全な例は 多対多のリレーションを持つモデルの例 を参照してください。
ManyToManyField フィールドはリレーションの動作を定義するための引数を
いくつかとれます。これらは全てオプションです:
| 引数 |
説明 |
| related_name |
前述の ForeignKey の説明を参照してください。 |
| filter_interface |
ユーザビリティが紙一重の <select multiple>
の代わりに、気の利いた控えめな Javascript の
「フィルタ」インタフェースを使います。値は
models.HORIZONTAL または models.VERTICAL
のいずれか (インタフェースを横ならびにするか縦
ならびするか) です。 |
| limit_choices_to |
ForeignKey の同名オプションの説明を参照し
てください。 |
| symmetrical |
自分自身への ManyToManyField を定義すると
きにのみ使います。以下のようなモデルを考えます:
class Person(models.Model):
friends = models.ManyToManyField("self")
Django がこのモデルを処理する際、自分自身に対
する ManyToManyField が定義されていること
を認識して、 Person クラスに
person_set 属性を追加しないようにします。
その代り、 ManyToManyField を対称的
(symmetrical) であるとみなします。すなわち、私
があなたの友達なら、あなたは私の友達である、と
いうようにです。
self に対する ManyToMany の関係に対称
性を望まない場合は、 symmetrical を
False にしてください。これにより、 Django
に逆参照用のデスクリプタを追加させ、
ManyToMany を非対称にできます。
|
| db_table |
多対多のリレーション情報を保存するために作成さ
れるテーブルの名前です。名前を指定しなければ、
Django はデフォルトの名前を使います。デフォル
トの名前は、結合する二つのテーブルの名前に基づ
いて決められます。 |
一対一のリレーション
一対一のリレーションを定義するには、 OneToOneField を使います。
このフィールドは他のフィールド型と同じように、モデルのクラス属
性に含めて使えます。
このリレーションがもっとも有用なのは、あるオブジェクトが別のオブジェクト
を何らかの形で「拡張」している場合の主キーとして使う場合です。
OneToOneField には固定引数が一つあり、リレーションを張る対象のクラスを
指定します。
例えば、「場所 (place)」のデータベースを作るときには、アドレス、電話番号、
といった標準的なものを作成します。その上で、レストランデータベースを作成
するときに、 Restaurant モデルの中に同じフィールドをつくるような
繰り返し作業 (repeat yourself) をする代わりに、場所データベースを基盤にして
レストランのデータベースを作成したいとしましょう。このとき、 Restaurant
には Place への OneToOneField をもたせられます (レストランは
場所に対して "is-a" の関係だからです)
ForeignKey と同じく、モデル名ではなく文字列 'self' を使えば自分自身
へのリレーションを定義できます。また、モデル名の入った文字列を使えば、未定
義のモデルも参照できます。
OneToOneField は以下のオプションを指定できます:
| 引数 |
説明 |
| parent_link |
他のモデルを継承しているモデル中で True に
すると、子のクラスのインスタンスから親のクラスの
インスタンスに向けたリンクのフィールドとして
使います。詳しくは モデルの継承 を参照してくださ
い。
開発版の Django で新たに追加された機能です
|
開発版の Django で新たに追加された機能: 以前は、モデル中で
OneToOneField を使うと、そのフィールドをモデルの主キーにしていました。
この仕様はもうなくなりましたが、主キーにしたければ手動で primary_key に
指定できます。この変更により、一つのモデル中で複数の OneToOneField を使
えるようになりました。
詳細な例は 一対一のリレーションを持つモデルの例 を参照してください。
カスタムのフィールド型
開発版の Django で新たに追加された機能です
既存のモデルフィールドが目的とするアプリケーションに合わない場合や、あまり
一般的でないデータベースカラムタイプを活用したい場合のために、独自のフィー
ルドクラスを作成できます。独自のフィールドの作成方法の詳細は
カスタムモデルフィールド のドキュメントで説明しています。
Meta オプション
モデルにメタデータを指定するには、以下のようにモデルの内部で
class Meta を使います:
class Foo(models.Model):
bar = models.CharField(max_length=30)
class Meta:
# ...
モデルのメタデータには、オブジェクトの並び規則など、「フィールドでないもの
全て」を入れます。
利用できる全ての Meta オプションのリストを以下に示します。どのオプショ
ンも Meta の記述に必須ではありません。モデルに class Meta を追加す
るかどうかもオプションです。
abstract
開発版の Django で新たに追加された機能です
True に設定すると、モデルを抽象ベースクラスにします。詳しくは
抽象ベースクラス の節を参照してください。デフォルト値は False です。
db_table
モデルの使うデータベーステーブルの名前です:
db_table = "music_album"
このオプションを指定しなければ、Django は
app_label + '_' + model_class_name を使います。詳しくは後述の「テーブル
名」を参照してください。
データベーステーブル名が SQL の予約語であったり、 Python 変数名として使えな
い文字を含んでいる場合 (よくあるのはハイフンです) でも問題はありません。
Django は背後でカラム名とテーブル名をクオートします。
get_latest_by
モデル中の DateField または DateTimeField の名前です。このオプショ
ンは、モデルの Manager の latest() メソッドが使うデフォルトのフィー
ルドを指定します。
例えば:
get_latest_by = "order_date"
完全な例は latest() のドキュメント を参照してください。
order_with_respect_to
オブジェクトを指定のフィールドで「並べ替え可能 (orderable)」にします。この
オプションを使うのは、リレーションの張られたオブジェクトを、親オブジェクト
に従って並べ替えたい場合がほとんどです。例えば、 Answer が Question
にリレーションを張っており、一つの Question に複数の Answer があっ
て、 Answer の順番が重要である場合は以下のようにします:
class Answer(models.Model):
question = models.ForeignKey(Question)
# ...
class Meta:
order_with_respect_to = 'question'
ordering
オブジェクトのリストを取得するときに使われる、オブジェクトのデフォルトの並
び順規則です:
ordering = ['-order_date']
値は文字列のタプルやリストです。各文字列はフィールドの名前で、降順に並べる
場合にはオプションの "-" を先頭に付けます。先頭に "-" のないフィールドは昇
順に並べられます。順番をランダムにするには "?" を使って下さい。
例えば、 pub_date フィールドで昇順に並べる場合には以下のようにします:
ordering = ['pub_date']
例えば、 pub_date フィールドで降順に並べる場合には以下のようにします:
ordering = ['-pub_date']
例えば、 pub_date フィールドで降順に並べ、さらに author で昇順に場
合には以下のようにします:
ordering = ['-pub_date', 'author']
その他の例は 並び順の指定例 を参照してください。
ordering にいくつフィールドがあっても、 admin サイトは最初のフィールド
しか使わないので注意してください。
permissions
オブジェクトの生成時にパーミッションテーブルに追加するパーミッションのリス
トです。 admin セットをもつオブジェクトには、追加、削除、変更のパーミッ
ションが自動的に生成されます。以下の例では、 can_deliver_pizzas という追
加のパーミッションを定義しています:
permissions = (("can_deliver_pizzas", "Can deliver pizzas"),)
(permission_code, human_readable_permission_name) の形式をとる 2 要素の
タプルからなるリストです。
unique_together
組み合わせとして一意にしなければならないフィールドセットのリストです:
unique_together = (("driver", "restaurant"),)
この制約は Django の admin 上で使われるとともに、データベースレベルでも強制
されます (すなわち、適切な UNIQUE 文が CREATE TABLE 文に入ります)。
unique_together に指定するフィールドは、全て同じモデルのフィールドでな
ければなりません。 モデルの継承 を行っている場合、親クラスのフィールドは
unique_together に指定できません。
開発版の Django で新たに追加された機能です
便宜上、 unique_together は一つのリストのときは単一セットのフィールドとして
扱います:
unique_together = ("driver", "restaurant")
verbose_name
人間可読なオブジェクト名の単数形です:
verbose_name = "pizza"
この引数を指定しない場合、Django はクラス名を解体した文字列を使います。例え
ば CamelCase は camel case になります。
verbose_name_plural
オブジェクトの複数形名です:
verbose_name_plural = "stories"
この引数を指定しない場合、Django は verbose_name + "s" を使います。
自動的な主キーフィールド
デフォルトでは、 Django は各モデルに以下のフィールド:
id = models.AutoField(primary_key=True)
を追加します。これは自動的に値をインクリメントして追加してゆくフィールドで、
主キーに使われます。
カスタムの主キーを指定したければ、いずれかのフィールドに
primary_key=True を指定してください。 primary_key が設定されている
のを Django が見つけると、 id カラムを自動的に追加しません。
各モデルには必ず一つ primary_key=True のフィールドが必要です。
pk プロパティ
開発版の Django で新たに追加された機能です
主キーを自前で定義しているか、 Django によって供給されているかに
関係なく、それぞれのモデルは pk と呼ばれるプロパティを持ちます。 これは
モデルの通常の属性のように振る舞いますが、実はモデルの主キーフィールド
のエイリアスです。その他の属性と同じように、この値は読み書き可能で、モデルの
フィールドを修正し更新できます。
Admin オプション
自作のモデルを admin サイト上で可視にするには、以下のようにモデルの内部で
"class Admin" を使います:
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
class Admin:
# オプションをここに記述します
pass
Admin クラスは admin サイト上でのモデルの表示方法を Django に教えます。
利用可能な Admin オプションのリストを示します。これらのクラス変数は全て
オプションです。オプションを全く指定せずに admin インタフェースを使いたけれ
ば、以下のように pass を使います:
class Admin:
pass
class Admin をモデルに追加するかどうかも全くのオプションです。
date_hierarchy
date_hierarchy をモデルの DateField や DateTimeField に指定する
と、変更リストのページに、指定フィールドの日付を使って日付ベースで絞り込み
できるナビゲーションが組み込まれます。
例:
date_hierarchy = 'pub_date'
fields
admin の「追加 (add)」および「変更 (change)」ページのレイアウトを制御するに
は、 fields を使います。
fields は 2 要素のタプルのリストです。各タプルは admin フォームページ上
の <fieldset> を表します (<fieldset> はフォームの「セクション」にな
ります)。
フィールドセットは (name, field_options) の形式をとります。 name
はフィールドセットの名前を表す文字列で、 field_options はフィールドセッ
トに表示すフィールドの情報を入れた辞書です。
django.contrib.flatpages.FlatPage モデルから抜き出した例を示します:
class Admin:
fields = (
(None, {
'fields': ('url', 'title', 'content', 'sites')
}),
('Advanced options', {
'classes': 'collapse',
'fields' : ('enable_comments', 'registration_required', 'template_name')
}),
)
このフィールドセットによって、 admin のページは以下のようになります:
fields を指定しない場合、 Django は AutoField でなくかつ
editable=True であるフィールドの各々を、モデルに定義した順番に
個別のフィールドセットとして表示します。
field_options 辞書には以下のようなキーがあります:
fields
フィールドセット内に表示するフィールド名からなるタプルです。必須のキーです。
例:
{
'fields': ('first_name', 'last_name', 'address', 'city', 'state'),
}
同じ行に複数のフィールドを表示したい場合、それらのフィールドをタプルでラッ
プして入れます。下の例では、 first_name と last_name が同じ行に
表示されます:
{
'fields': (('first_name', 'last_name'), 'address', 'city', 'state'),
}
classes
フィールドセットに適用される追加の CSS クラス名です。単純な文字列を指定しま
す。
例:
{
'classes': 'wide',
}
また、以下の例のように、スペースで区切ると複数のクラスを適用できます:
{
'classes': 'wide extrapretty',
}
デフォルトのスタイルシートで定義されている便利なクラスとして collapse
や wide があります。 collapse スタイルのフィールドは、 admin ページ
では最初折り畳まれ (collapse) ており、小さな "クリックして展開 (click to
expand)" リンクに置き換わっています。 wide スタイルのフィールドセットに
は水平方向に追加のスペースが加わります。
description
各フィールドセットの先頭に表示する追加の文字列で、オプションです。この文字
列はそのまま表示されるので、 HTML を使えますし、 HTML で特別扱いされる文字
(アンパーサンドなど) は自分でエスケープしておかねばなりません。
js
JavaScript ファイルの URL を表す文字列のリストです。 JavaScript は admin ス
クリーンに <script src="" タグでリンクされます。このオプションは、特定
の admin ページを JavaScript で操作したり、特定のフィールドにデフォルト値を
埋めるための "quick link" を提供したりするために使えます。
http:// や / で始まらない相対 URL を使うと、 Django の admin はリン
クに settings.ADMIN_MEDIA_PREFIX をプレフィクスします。
list_display
admin の変更リストページに表示するフィールドを制御するには list_display
を使います。
例:
list_display = ('first_name', 'last_name')
list_display を指定しなければ、 admin サイトは各オブジェクトの
__str__() 表現を表示するカラムを一つだけ表示します。
list_display にはいくつか特殊なケースがあります:
フィールドが ForeignKey の場合、関連づけられているオブジェクトの
__unicode__() を表示します。
ManyToManyField フィールドの表示は、テーブルの各行に対して個別に
SQL 文を実行することになってしまうのでサポートしていません。どうして
も表示させたいなら、カスタムメソッドをモデルに実装して、メソッドの名
前を list_display に追加してください (list_display へのカスタ
ムメソッドの追加については、後で詳しく説明しています)。
フィールドが BooleanField や NullBooleanField の場合、
True や False の代りに "オン" や "オフ" を示すアイコンを表示
します。
フィールド名がモデルのメソッドになっていた場合、メソッドを呼び出
した結果を表示します。このメソッドには、フィールドのヘッダに使うた
めの short_description という関数属性がなければなりません。
例を示します:
class Person(models.Model):
name = models.CharField(max_length=50)
birthday = models.DateField()
class Admin:
list_display = ('name', 'decade_born_in')
def decade_born_in(self):
return self.birthday.strftime('%Y')[:3] + "0's"
decade_born_in.short_description = 'Birth decade'
渡された文字列がモデルのメソッド名の場合、 Django はデフォルトでメソッ
ドの出力をエスケープします。メソッドの出力をエスケープしたくない場合
には、メソッドの allow_tags 属性の値を True にしてください。
以下にモデル例を示します:
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
color_code = models.CharField(max_length=6)
class Admin:
list_display = ('first_name', 'last_name', 'colored_name')
def colored_name(self):
return '<span style="color: #%s;">%s %s</span>' % \
(self.color_code, self.first_name, self.last_name)
colored_name.allow_tags = True
渡された文字列がモデルのあるメソッドを指しており、メソッドが True か
False を返す場合、メソッドの boolean 属性を True に設定してお
くと、Django は "on" や "off" のアイコンを表示します。
以下に最終的なモデルの例を示します:
class Person(models.Model):
first_name = models.CharField(max_length=50)
birthday = models.DateField()
class Admin:
list_display = ('name', 'born_in_fifties')
def born_in_fifties(self):
return self.birthday.strftime('%Y')[:3] == 5
born_in_fifties.boolean = True
__str__() および __unicode__() メソッドは他のモデルメソッドと
同じように list_display に入れられるので、以下のように書いても全
く問題ありません:
list_display = ('__unicode__', 'some_other_field')
list_display の要素のうち、モデルのフィールドでないものには、変更
リストページで並び順を変えるときのカラムには使えません。これは Django
がオブジェクトの整列をデータベースレベルで行っており、カスタムメソッ
ドがどうやってオブジェクトを整列するかを SQL レベルで知る術がないため
です。
通常、 list_display の要素のうち、モデルのフィールドでないものに
は、変更リストページで並び順を変えるときのカラムには使えません。
(Django はソートをすべてデータベースレベルで行うからです)
list_display の要素が実際にデータベース上のあるフィールドを指して
いる場合、 admin_order_field という属性を使って、 Django にそのこ
とを教えられます。例えば:
class Person(models.Model):
first_name = models.CharField(max_length=50)
color_code = models.CharField(max_length=6)
class Admin:
list_display = ('first_name', 'colored_first_name')
def colored_first_name(self):
return '<span style="color: #%s;">%s</span>' % (self.color_code, self.first_name)
colored_first_name.allow_tags = True
colored_first_name.admin_order_field = 'first_name'
この例では、 Django は Admin 上で colored_first_name を並べ変える
際に first_name フィールドを使います。
list_display_links
list_display_links を設定すると、 list_display のどのフィールドを
オブジェクトの「変更」ページにリンクするかを制御できます。
デフォルトでは、変更リストページはオブジェクトの変更ページ中の第一カラム、
すなわち list_display の先頭に指定したフィールドにリンクを張ります。
list_display_links を使うと、リンク先のカラムを変更できます。
list_display_links には、フィールド名のリストまたはタプルを
(list_display と同じ形式で) 指定します。
list_display_links に指定するフィールド名は、一つでも複数でも構いません。
フィールド名が list_display に列挙されている限り、 Django はどんなに多
くの (あるいはどんなにわずかな) フィールドがリンクされていても問題にしませ
ん。必要なのは、 list_display_links を使うには list_display を定義
しておかねばならない、ということだけです。
以下の例では、 first_name および last_name フィールドが変更変更リス
トページにリンクされます:
class Admin:
list_display = ('first_name', 'last_name', 'birthday')
list_display_links = ('first_name', 'last_name')
最後に、 list_display_links を使うには list_display も指定せねばな
らないので注意しましょう。
list_filter
admin の変更リストページの右側のサイドバーにあるフィルタを有効にするには、
list_filter を設定します。この値はフィールド名のリストにします。
各フィールド名は BooleanField, CharField, DateField,
DateTimeField, IntegerField, ForeignKey のいずれかでなければ
なりません。
以下の例は django.contrib.auth.models.User モデルからとったもので、
list_display と list_filter の仕組みを示しています:
class Admin:
list_display = ('username', 'email', 'first_name', 'last_name',
'is_staff')
list_filter = ('is_staff', 'is_superuser')
上のコードによって、 admin の変更リストは以下のようになります:
(この例では、後述する search_fields も定義しています。)
list_per_page
admin 変更リストをページ分割 (paginate) で表示するときに、各ページに何個の
アイテムを表示するかを決めます。デフォルト値は 100 です。
ordering
ordering を設定すると、 admin の更新リストにおける整列順を指定できます。
値はタプルからなるリストで、モデルの ordering パラメタと同じ形式で指定
します。
save_as
save_as を指定すると、オブジェクト編集ページで「別名で保存 (save as)」
機能を使えるようになります。
通常、オブジェクト編集ページには三つの保存オプション、すなわち「保存
(Save)」、「保存して編集を続ける (Save and continue editing)」、「保存して
もう一つ追加 (Save and add another)」があります。 save_as を True
にすると。「保存してもう一つ追加」は「別名で保存 (Save as)」に置き換わりま
す。
「別名で保存」は、現在のオブジェクトをそのまま保存するのではなく、(新たな
ID を持った) 別のオブジェクトとして保存することです。
save_on_top
save_on_top を指定すると、 admin の変更フォームの最上部に保存ボタンを追
加できます。
通常、保存ボタンはフォームの最下部だけに表示されます。 save_on_top を指
定すると、ボタンは最下部だけでなく最上部にも表示されます。
デフォルトでは、 save_on_top は False です。
search_fields
search_fields を指定すると、 admin の変更リストページで検索ボックスを使
えるようになります。この値はユーザが検索クエリをテキストボックスに入力した
ときに検索の対象になるフィールド名のリストです。
フィー ルドは CharField や TextField のような何らかのテキストフィー
ルドでなければなりません。 DB 照合 API の「リレーション追跡」表記を使えば、
ForeignKey を介したフィールドの指定も行えます:
search_fields = ['foreign_key__related_fieldname']
admin の検索ボックスで検索を実行すると、 Django は検索クエリを単語に分解し
て、各単語を含むような全てのオブジェクトを返します。検索は大小文字を区別せ
ず、 search_fields に指定したフィールドのうち少なくとも一つに単語が入っ
ていればヒットします。例えば、 search_fields が
['first_name', 'last_name'] に設定されている場合、ユーザが
john lennon を検索すると、 Django は以下のような WHERE 節を持った
SQL に等価な検索を実行します:
WHERE (first_name ILIKE '%john%' OR last_name ILIKE '%john%')
AND (first_name ILIKE '%lennon%' OR last_name ILIKE '%lennon%')
より高速な、あるいはより制約の厳しい検索を行うには、フィールド名の前に以下
のような演算子を置きます:
- ^
フィールドの先頭にマッチします。例えば、 search_fields を
['^first_name', '^last_name'] にして、ユーザが john lennon を検
索した場合、Django は以下のような WHERE 節の SQL に等価な検索を実行
します:
WHERE (first_name ILIKE 'john%' OR last_name ILIKE 'john%')
AND (first_name ILIKE 'lennon%' OR last_name ILIKE 'lennon%')
このクエリを使うと、データベースはカラムの先頭部分だけをチェックすれば
よく、カラム中のデータ全体を調べなくてもよくなるため、通常の
'%john%' クエリよりも効率的になります。加えて、カラムにインデクスが
設定されていれば、データベースによっては LIKE クエリであってもイン
デクスを使ったクエリを実行できるという利点があります。
- =
大小文字を区別しない厳密一致です。例えば、 search_fields を
['=first_name', '=last_name'] にして、ユーザが john lennon を検
索した場合、 Django は以下のような WHERE 節の SQL に等価な検索を実行
します:
WHERE (first_name ILIKE 'john' OR last_name ILIKE 'john')
AND (first_name ILIKE 'lennon' OR last_name ILIKE 'lennon')
クエリ入力はスペース区切りなので、この例に従うと、 first_name が
'john winston' (スペースを含むもの) であるようなレコードは検索でき
ないので注意してください。
- @
- 全文検索マッチを実行します。デフォルトの search メソッドに似ていますが、
インデクスを使います。現在のところ MySQL でしか使えません。
モデルのメソッド
カスタムの行レベル ("row-level") の機能をオブジェクトに実装するには、カスタ
ムのメソッドを定義します。 Manager メソッドの目的が「テーブル級
(table-wide)」 の操作であるのに対し、モデルメソッドは個々のモデルインスタン
スに対して作用します。
このモデルメソッドは、ビジネスロジックをモデルというただ一箇所にまとめてお
くのに有用なテクニックになります。
例えば、以下のモデル例にはいくつかカスタムメソッドがあります:
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
birth_date = models.DateField()
address = models.CharField(max_length=100)
city = models.CharField(max_length=50)
state = models.USStateField() # Yes, this is America-centric...
def baby_boomer_status(self):
"Returns the person's baby-boomer status."
import datetime
if datetime.date(1945, 8, 1) <= self.birth_date <= datetime.date(1964, 12, 31):
return "Baby boomer"
if self.birth_date < datetime.date(1945, 8, 1):
return "Pre-boomer"
return "Post-boomer"
def is_midwestern(self):
"Returns True if this person is from the Midwest."
return self.state in ('IL', 'WI', 'MI', 'IN', 'OH', 'IA', 'MO')
def _get_full_name(self):
"Returns the person's full name."
return '%s %s' % (self.first_name, self.last_name)
full_name = property(_get_full_name)
この例の最後のメソッドは プロパティ (property) です。詳しくは
プロパティの説明 を参照してください。
いくつかのメソッドには特別な意味があります:
__str__
__str__() は、オブジェクトに対して str() を呼び出した際に返す内容を
定義するための Python の特殊メソッドです。 Django はそこかしこで
str(obj) (または unicode(obj) -- 下記参照) を使っています。ほとんど
は、 Django の admin サイトでオブジェクトをレンダリングして表示したときの値
として、またオブジェクトを表示するときにテンプレートに挿入される値として使
われています。従って、オブジェクトの __str__ は、人間可読なわかりやすい
文字列を返さねばなりません。必須ではありませんが、強く推奨します (ただし、
そこかしこに __str__ メソッドを突っ込んでしまう前に __unicode__ の
説明を良く読んでくださいね)。
例えば:
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
def __str__(self):
# first_name および last_name は Unicode 文字列なので、
# django.utils.encoding.smart_str() を使っています。
return smart_str('%s %s' % (self.first_name, self.last_name))
__unicode__
__unicode__() メソッドは、オブジェクトに対して unicode() を呼び出し
た際に呼び出されます。Django のデータベースバックエンドはモデルの属性値とし
て Unicode 文字列を返すので、通常はモデルの __unicode__() メソッドを定
義するとよいでしょう。前節の例を __unicode__() を使って書き直すと、以下
のように簡単になります:
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
def __unicode__(self):
return u'%s %s' % (self.first_name, self.last_name)
モデルに __unicode__() メソッドだけを定義して、 __str__() は定義し
ないでおくと、 Django が自動的に __str__() メソッドをモデルに追加します。
この __str__() メソッドは、 __unicode__() を呼び出して、その戻り値
を UTF-8 でエンコードした文字列を返します。開発上はこの仕様に従い、
__unicode__() だけを定義して、文字列オブジェクトへの変換は Django 任せ
にするよう勧めます。
get_absolute_url
オブジェクトの URL の計算方法を Django に教えるには get_absolute_url メ
ソッドを定義してください。例えば:
def get_absolute_url(self):
return "/people/%i/" % self.id
Django はこのメソッドを admin インタフェースで使います。オブジェクトが
get_absolute_url() を定義していた場合、オブジェクトの詳細ページには「サ
イト上で表示 (View on site)」というリンクが表示されます。このリンクは、オブ
ジェクトの get_absolute_url() に基づいて、オブジェクトを公開しているビュー
に直接飛べるようになっています。
また、その他にも、例えば 配信フィードフレームワーク などで、
get_absolute_url() を使うことでユーザの利便性を高めています。
テンプレートでオブジェクトの URL を表示する場合、ハードコードするのでは
なく get_absolute_url() を使うようにするとよいでしょう。例えば、以下の
テンプレート:
<a href="/people/{{ object.id }}/">{{ object.name }}</a>
は良い例ではなく、以下のようにするとよいでしょう:
<a href="{{ object.get_absolute_url }}">{{ object.name }}</a>
Note
get_absolute_url() の返す文字列は ASCII 文字だけで構成しなければな
りません (RFC 2396 の URI 仕様でそのように要求されています)。また、
必要に応じて URL エンコードせねばなりません。 get_absolute_url() を
使うコードやテンプレートが、 get_absolute_url() の返す文字列を、追
加の処理を施さなくても直接利用できるようにせねばならないのです。
URI に Unicode 文字列を沢山使っているのなら、
django.utils.encoding.iri_to_uri も使うことになるでしょう。
permalink デコレータ
上に述べた get_absolute_url() の問題は、いささか DRY 則の侵犯である、す
なわち URLconf とモデルの両方で URL が定義されているという点です。
permalink デコレータを使うと、 URLconf からモデルを脱カップリングできま
す。このデコレータには、ビュー関数、引数のリスト、そして (オプションとして)
名前つきパラメタの入った辞書を指定します。これらの情報から、 Django は
指定したパラメタで URLconf を置き換えて完全な URL パスを計算します。例えば、
以下のような URLconf が定義されていたとしましょう:
(r'^people/(\d+)/$', 'people.views.details'),
また、モデルの get_absolute_url メソッドは以下のように定義できます:
from django.db.models import permalink
def get_absolute_url(self):
return ('people.views.details', [str(self.id)])
get_absolute_url = permalink(get_absolute_url)
また、以下のような URLconf のエントリがあったとします:
(r'/archive/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/$',
archive_view)
permalink は以下のように使えます:
def get_absolute_url(self):
return ('archive_view', (), {
'year': self.created.year,
'month': self.created.month,
'day': self.created.day})
get_absolute_url = permalink(get_absolute_url)
この例では、第 2 引数に空の配列 (空のタプル) を指定していますが、これは引数
リストを渡さず、キーワード引数だけを渡したいからです。
permalink を使えば、 URL に関する情報を繰り返すことなく、モデルの絶対
URL と表示に使ったビューを結びつけられます。以前と同様、
get_absolute_url はテンプレート中でも使えます。
汎用ビューを使う場合や、複数のモデルに対して同じビューを再利用する場合、ビュー
関数そのものを指定すると、(複数のパターンが同じビューを指してしまうため)
URLディスパッチャが混乱をきたします。
この問題を解決するために、 Django には 名前つき URL パターン があります。
名前つき URL パターンを使えば、 URL パターンに固有の名前をつけておき、ビュー
関数の代わりに参照できます。名前つき URL パターンを定義するには、タプル表記
の URL パターンを url 関数に置き換えます:
from django.conf.urls.defaults import *
url(r'^people/(\d+)/$',
'django.views.generic.list_detail.object_detail',
name='people_view'),
この名前を使って、URL からビューの名前を以下のようにして逆解決します:
from django.db.models import permalink
def get_absolute_url(self):
return ('people_view', [str(self.id)])
get_absolute_url = permalink(get_absolute_url)
名前つき URL パターンの詳細は URL ディスパッチャのドキュメント
を参照してください。
カスタム SQL の実行
自作のモデルメソッドやモジュールレベルのメソッドでは、自由にカスタムの SQL
文を書けます。 django.db.connection というオブジェクトが現在のデータベー
ス接続を表現しています。カスタムSQL を使うには、まず
connection.cursor() を呼び出してカーソルオブジェクトを取得し、次いで
cursor.execute(sql, [params]) を呼び出して SQL を実行した後、
cursor.fetchone() や cursor.fetchall() を読んで結果行を返します。例
えば:
def my_custom_sql(self):
from django.db import connection
cursor = connection.cursor()
cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz])
row = cursor.fetchone()
return row
connection や cursor は標準の Python DB-API が提供する機能の
(トランザクションの扱い を除いた) ほとんどを実装しています。
Python DB-API に詳しくないのなら、上の SQL 文の cursor.execute() でパラ
メタを直接 SQL に入れるのではなく、プレースホルダ "%s" を使っていること
に注意して下さい。このテクニックを使うと、根底にあるデータベースライブラリ
は必要に応じて自動的にパラメタをクオートしたりエスケープ処理したりします。
(また、Django はプレースホルダ文字として SQLite の Python バインディングが
使っている "?" ではなく "%s" を使うので注意してください。これは
インタフェースに一貫性をもたせるための設計です。)
注意: WHERE 節を自分で設定したいだけなら、標準の照合 API に where
や tables 、 params といった引数を指定して実現できます。
extra() のドキュメント を参照してください。
デフォルトモデルメソッドのオーバライド
データベース API のドキュメント でも説明したように、 Django は各モデルに
自動的にいくつかメソッドを追加します。 save() や delete() がその例
です。これらのメソッドをオーバライドすれば、その挙動を変更できます。
組み込みメソッドをオーバライドする古典的なユースケースは、オブジェクトを保
存する際に何か別の処理を行うというものです。例えば:
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def save(self):
do_something()
super(Blog, self).save() # 「実際の」 save() を呼び出します。
do_something_else()
また、以下のようにすれば保存を抑止できます:
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def save(self):
if self.name == "Yoko Ono's blog":
return # Yoko は自分のブログを持っていません!
else:
super(Blog, self).save() # 「実際の」save() を呼び出します。
モデルの継承
開発版の Django で新たに追加された機能です
Django のモデルクラス継承は、 Python の通常のクラス継承とほぼ同じように動作
します。モデル継承を実現するには、一つだけきめておかねばならないことがあり
ます。それは、親クラスに独自のデータベーステーブルを持たせるか、親クラスを
単なるホルダとして使い、子クラスで共通の情報を持たせるだけにするかです。
複数の子モデルクラスでいちいち同じ情報を入力せずに済ませるために、親モデル
クラスに共通の情報を持たせたいことはよくあります。親モデルクラスを単体で使
うことがないのなら、 抽象ベースクラス を使うのがよいでしょう。一方、(他
のアプリケーションなどにある) 既存のモデルをサブクラス化して拡張したり、個々
のモデルに固有のデータベースを持たせたいような場合には、
マルチテーブル継承 を使うのがよいでしょう。
抽象ベースクラス
抽象ベースクラスは、たくさんのモデルで共通の情報を入れておきたいときに便利
な仕組みです。抽象ベースクラスを定義するには、ベースクラス定義の、 Meta
に abstract=True を入れておきます。モデルを抽象ベースクラスとして定義す
ると、そのクラスはデータベーステーブルを生成しません。その代り、他のモデル
を定義するときに抽象ベースクラスを親にすると、ベースクラスのフィールドが子
クラスに追加されます。抽象ベースクラスで定義したフィールドと同じ名前のフィー
ルドを子クラスで定義しようとするとエラーを引き起こします (Django は例外を送
出します)。
例を示しましょう:
class CommonInfo(models.Model):
name = models.CharField(max_length=100)
age = models.PositiveIntegerField()
class Meta:
abstract = True
class Student(CommonInfo):
home_group = models.CharField(max_length=5)
このように定義すると、 Student モデルは name, age および
home_group の三つのフィールドを持つようになります。. CommonInfo モ
デルは抽象ベースクラスなので、通常の Django モデルとしては使えません。
CommonInfo はデータベーステーブルを作らず、マネジャなども持ちません。
ほとんどの用途で使えるのは、このタイプのモデル継承でしょう。抽象ベースクラ
スは、子クラスで共通の情報を Python レベルに切り出しながらも、データベース
レベルでは、各子クラに一つのデータベーステーブルを生成します。
Meta の継承
抽象ベースクラスを作成するとき、 Django は抽象ベースクラスの内部クラス
Meta をクラス属性として参照できるようにします。子クラスで Meta
クラスを定義しない場合、親クラスの Meta がそのまま継承されます。
子クラスで Meta を拡張したければ、親クラスをサブクラス化できます。
以下に例を示しましょう:
class CommonInfo(models.Model):
...
class Meta:
abstract = True
ordering = ['name']
class Student(CommonInfo):
...
class Meta(CommonInfo.Meta):
db_table = 'student_info'
Django は抽象ベースクラスの Meta クラスを生成するときに一つだけ手を加え
ます。すなわち、 Meta の属性を組み込む前に、 abstract=False を設定
するのです。これにより、抽象ベースクラスの子クラスが自動的に非抽象ベースク
ラスになります。もちろん、他の抽象ベースクラスを継承した新たな抽象ベースク
ラスも定義できます。継承するには、明示的に abstract=True をセットしてく
ださい。
Meta クラスの属性の中には、抽象ベースクラスで定義しても意味のないものも
あります。例えば、 db_table を抽象ベースクラスの Meta で定義すると、
その子クラス全て (で、独自に Meta を定義しないもの) が、同じデータベー
ステーブルを使おうとしてしまいます。
マルチテーブル継承
Django では、継承の各階層にいるクラスが抽象クラスでない実際のモデルであるよ
うな、もう一つのタイプのモデル継承をサポートしています。各モデルはそれぞれ
が一個のデータベーステーブルを表現していて、個別にクエリを発行したり、イン
スタンスを生成したりできます。継承の関係によって、親クラスと子クラスの間に
は (自動生成された OneToOneField によって) リンクが張られます。以下の例
で説明しましょう:
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
class Restaurant(Place):
serves_hot_dogs = models.BooleanField()
serves_pizza = models.BooleanField()
Place の全てのフィールドは、 Restaurant からも使えます。しかし、そ
れぞれのフィールドのデータは別々のテーブルに格納されます。従って、以下のよ
うな操作をどちらも実行できます:
>>> Place.objects.filter(name="Bob's Cafe")
>>> Restaurant.objects.filter(name="Bob's Cafe")
例えば、 Place であり、かつ Restaurant でもあるようなオブジェクトが
あれば、モデル名を小文字にした属性を使って、 Place から Restaurant
を取り出せます:
>>> p = Place.objects.filter(name="Bob's Cafe")
# Bob's Cafe が Restaurant オブジェクトなら、子クラスを返す:
>>> p.restaurant
<Restaurant: ...>
ただし、上の p が Restaurant クラスで ない のなら (Place から
直接生成されたオブジェクトや、他のクラスの親クラスなら) p.restaurant
はエラーを引き起こします。
Meta とマルチテーブル継承
マルチテーブル継承では、子クラスが親クラスの Meta クラスを継承する意味
がありません。 Meta オプションは全て親クラスだけに適用されるべきもので、
他のクラスに同じ内容を適用しても、矛盾した振る舞いを引き起こすだけです
(これは、独自のテーブルを持たない抽象ベースクラスと対照的な部分です)。
従って、マルチテーブル継承の子クラスは親クラスの Meta クラスにアクセス
する方法を持ちません。ただし、限られたケースで、子クラスが親クラスの挙動を
継承する場合があります。それは、子クラスで ordering または
get_latest_by 属性を指定していない場合に、親クラスの属性を継承するとい
うものです。
親クラスで整列カラムが指定されていて、子クラス側で整列カラムを指定したくな
い場合は、明示的に空の整列カラムを指定してください:
class ChildModel(ParentModel):
...
class Meta:
# 親クラスの整列カラム設定の効果を除去する
ordering = []
継承と逆リレーション
マルチテーブル継承は親クラスと子クラスを暗黙の OneToOneField でリンクす
るので、前述の例のように、親クラスから子クラスをたどれます。しかし、子クラ
スをたどるときに使う名前は、 ForeignKey や ManyToManyField リレーショ
ンを定義したときのデフォルトの related_name と同じ値を使っています。
従って、子クラスで ForeignKey や ManyToManyField を別のクラスに向け
て張るときには、 必ず related_name をフィールドに指定せねばなりませ
ん。指定し忘れると、 Django は manage.py validate や syncdb 時にエ
ラーを送出します。
例えば、上の Place クラスに対して、 ManyToManyField を持った別のサ
ブクラスを定義してみましょう:
class Supplier(Place):
# 全てのリレーションで related_name を定義すること
customers = models.ManyToManyField(Restaurant,
related_name='provider')
逆リレーションの詳細は、 データベース API リファレンス を参照してくださ
い。とりあえずは、マルチテーブル継承で新たなモデルを作成したときには、
manage.py validate を実行して、エラーメッセージが出ないか確かめるように
しましょう。
親クラスのリンクフィールドを定義する
すでに触れたように、 Django は子クラスと抽象クラスでない親クラスにリンクし
た OneToOneField を自動的に生成します。親クラスへのリンク名を操作したけ
れば、自分で OneToOneField を作成し、パラメタに parent_link=True を
渡してください。例えば、上の例で Supplier から Place への明示的なリ
ンクフィールドを作成するには、以下のようにします:
class Supplier(Place):
parent = models.OneToOneField(Place, parent_link=True)
...
多重継承
Python のサブクラスと同様、 Django のモデルも複数の親モデルクラスを継承でき
ます。クラス内の名前解決には、 Python の通常の名前解決規則が適用されるので
注意してください。子クラスで特定の名前 (例えば Meta) を参照する場合、そ
の名前を定義している最初のベースクラスの定義を使い、最初に名前が見つかった
時点で、それ以降同じ名前のオブジェクトの解決は行われません。従って、複数の
親クラスで別々に Meta クラスを定義していても、最初のベースクラスの
Meta だけが使われ、それ以外は全て無視されます。
通常は、モデルの多重継承は必要ないでしょう。多重継承が便利なのは、主に特定
のフィールドやメソッドを追加するための ''mix-in'' クラスを使う場合です。
継承の階層構造はできるだけ単純に、分かりやすくしておきましょう。さもないと、
子クラスで扱っている情報が、どの親クラスから来たか調べるために四苦八苦する
はめになるでしょう。
SQL 初期化データの提供
Django では、 CREATE TABLE 文を実行した直後に任意の SQL をデータベースに渡
せるフックを提供しています。例えば、このフックを使えば、自動的にデフォルト
のレコードをテーブルに追加したり SQL 関数を作成したりできます。
フックのからくりは単純です: Django は <appname> をアプリケーションディ
レクトリの名前、 <modelname> をモデル名を小文字にした文字列として、
<appname>/sql/<modelname>.sql を探すようになっているだけです。
このドキュメントの冒頭にある Person の例で、モデルが myapp の下に置
かれていたとすると、 myapp/sql/person.sql というファイルに任意の SQL 文を指定できます。例えば以下のような命令を入れられます:
INSERT INTO myapp_person (first_name, last_name) VALUES ('John', 'Lennon');
INSERT INTO myapp_person (first_name, last_name) VALUES ('Paul', 'McCartney');
各 SQL ファイルには有効な SQL 文を入れておかねばなりません。 SQL ファイルは
モデルのテーブルを生成する SQL が実行された直後にデータベースに直接パイプ入
力されます。
SQL ファイルは manage.py の sqlcustom, sqlreset,
sqlall および reset コマンドの実行時に参照されます。詳しくは
manage.py のドキュメント を参照してください。
複数の SQL データファイルがある場合、個々のファイルを実行する順番は保証され
ていないので注意して下さい。仮定していてよいのは、カスタムの SQL データファ
イルを実行する前に、必ずデータベーステーブルは作成されているということだけ
です。
データベースバックエンド特有の SQL データ
バックエンド特有の SQL データに対するフックもあります。例えば、 PostgreSQL
と MySQL 向けに別々の初期データを用意するのなら、各アプリケーションごとに
Django は <appname>/sql/<modelname>.<backend>.sql というファイルを探し
ます。 <appname> はアプリケーションディレクトリの名前、 <modelname>
はモデル名を小文字にした文字列、 <backend> は設定ファイルの
DATABASE_ENGINE に指定するバックエンドの名前 (postgresql, mysql
など) です。
バックエンド固有の SQL データは、バックエンド非固有の SQL データよりも前に
実行されます。例えば、アプリケーション中に sql/person.sql および
sql/person.postgresql.sql が入っていて、 PostgreSQL をバックエンドにし
てインストールを行った場合、 Django はまず sql/person.postgresql.sql の
内容を実行してから sql/person.sql を実行します。