モデルの作成

revision-up-to:17812 (1.4)

モデルとは、サイトを構成するデータの、唯一絶対的なデータソースを指します。 モデルには、保存したいデータを表すデータフィールドと、データのビヘイビアを 定義します。通常、一つのモデルは一つのデータベーステーブルに対応しています。

モデルの基本として、以下のことを知っておいてください:

  • 各モデルは Python のクラスで、 django.db.models.Model のサブ クラスです。
  • モデルの各アトリビュートの値は、データベース上のあるフィールドを表現 します。
  • モデルの情報をもとに、 Django はデータベース API を自動生成します。 API の詳細は「 クエリを生成する 」で解説します。

簡単な例

以下の例では、 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_namelast_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 を発行します。

モデルを使う

モデルを定義したら、そのモデルを 使う よう Django に指示しましょう。設定 ファイルを編集して、 models.py の入っているパッケージの名前を INSTALLED_APPS 設定に追加してください。

例えば、アプリケーションのモデルが mysite.myapp.models モジュール (mysite.myappmanage.py startapp スクリプトで 作成したアプリケーションのパッケージ) に入っているなら、 INSTALLED_APPS に以下のように書きます:

INSTALLED_APPS = (
    #...
    'mysite.myapp',
    #...
)

新しいアプリケーションを INSTALLED_APPS に追加したら、 manage.py syncdb を忘れずに実行してください。

フィールド

モデルのフィールドは、モデルの定義で最も重要な、かつ最小限必要な要素です。 フィールドは、以下の例のように、クラスのアトリビュートとして定義します:

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

フィールドのタイプ

モデルの各フィールドには、 Field クラスのサブク ラスから、適切なクラスのインスタンスを生成して入れます。Django は、フィール ドのクラスが何であるかという情報を、以下のような判定で使います:

  • データベースのカラム型 (INTEGER, VARCHAR など) の決定
  • Django の管理サイトで使うウィジェット (<input type="text">, <select> など) の決定
  • Django の管理サイトやマニピュレータが実施する最小限のバリデーション の決定

Django にはたくさんのフィールドクラスが組み込みで付属しています。組み込みの フィールドクラス一覧は「 モデルフィールドリファレンス 」にあります。組み込みのフィールドで実現できないことが あれば、フィールドクラスを自分で定義できます。 「 howto-custom-model-fields 」を参照してください。

フィールドのオプション

各フィールドクラスには、それぞれフィールド固有の引数がいくつかあります (詳 しくは「 モデルフィールドリファレンス 」を参照し てください)。例えば、 CharField (とそのサブクラ ス) には、データを保存するときの VARCHAR データベースフィールドの長さを 決める必須の引数、 max_length が必要で す。

また、全てのフィールドに共通の引数もあります。共通の引数はどれも省略可能で す。共通の引数は「 リファレンス 」で説 明しています。

ここでは、良く使う引数を簡単に紹介しましょう:

null
True にすると、フィールドの値が空のとき、データベースには NULL を保存します。デフォルトの設定は False です。
blank

True にすると、フィールドの値を空白 (blank) にできます。デフォ ルトの設定は False です。

null とは違うので注意してください。 null は、単に空のデータをデータベース上でどう表現す るかを決めています。一方、 blank はフィールドの値の 検証 (validation) 方法を決めています。あるフィールドに blank=True を指定すると、 Django の管理サイト 上で、そのフィールドを空の値にしたままエントリを作れます。 blank=False にすると、フィールドには必ず値を 入れねばなりません。

choices

iterable (リストまたはタプル) を指定します。 iterable の各要素は フィールドの値の選択肢を表す 2 要素のタプルです。 choices を指定すると、 Django の管理サイト上には、標 準的なテキストフィールドの代わりにセレクタボックスが表示され、ユー ザは選択肢の値だけを選べます。

選択肢のタプル列は、例えば以下のように定義します:

YEAR_IN_SCHOOL_CHOICES = (
    ('FR', 'Freshman'),
    ('SO', 'Sophomore'),
    ('JR', 'Junior'),
    ('SR', 'Senior'),
    ('GR', 'Graduate'),
)

各タプルの最初の要素が実際にデータベースに保存される値で、二つめの 要素が管理インタフェースや ModelChoiceField に表示される内容で す。あるモデルオブジェクトのインスタンスで後者の値 (表示値) を取り 出したければ、 get_FOO_display メソッドを使います。例えば、以下 のようなモデルを考えましょう:

from django.db import models

class Person(models.Model):
    GENDER_CHOICES = (
        (u'M', u'Male'),
        (u'F', u'Female'),
    )
    name = models.CharField(max_length=60)
    gender = models.CharField(max_length=2, choices=GENDER_CHOICES)

gender の表示値は get_gender_display で取り出します:

>>> p = Person(name="Fred Flinstone", gender="M")
>>> p.save()
>>> p.gender
u'M'
>>> p.get_gender_display()
u'Male'
default
フィールドのデフォルト値です。この値は、固定の値でも、関数などの呼 び出し可能オブジェクトでもかまいません。呼び出し可能オブジェクトに した場合、新たなモデルインスタンスを生成するたびにそのオブジェクト を呼び出して、フィールドのデフォルト値を動的に決定します。
help_text
管理サイトでフォームの下に表示される、詳しい「ヘルプ」テキストです。 管理サイトを使っていなくても、定義しておけばドキュメントとして役に 立ちます。
primary_key

True を指定すると、フィールドをモデルの主キーにします。

モデルのどのフィールドにも primary_key=True が指定されていない場合、Django は自動的に IntegerField を追加して主キーを保存します。従って、主キー の設定をデフォルトの状態から変更したいのでないかぎり、 primary_key=True を指定する必要はありま せん。詳しくは「 主キーフィールドの自動設定 」を参照してく ださい。

unique
True の場合、フィールドの値はテーブル全体で一意でなければなりま せん。

前置きしたように、ここではよく使うオプションを簡単に説明するにとどめます。 全オプションの詳しい情報は 「 共通のモデルフィールドオプションのリファ レンス 」を参照してください。

主キーフィールドの自動設定

デフォルトの動作では、 Django は各モデルに以下のフィールド:

id = models.AutoField(primary_key=True)

を追加します。このフィールドは主キーに使われ、フィールドの値はレコードの追 加ごとに自動的にインクリメントされてゆきます。

特定のフィールドを主キーにしたければ、フィールドのオプションに primary_key=True を指定してください。 Field.primary_key の設定されたフィールドの定義があれば、Django は id カラムを自動的に追加しません。

各モデルには必ず一つ primary_key=True のフィー ルドが必要です。

表示用のフィールド名

ForeignKeyManyToManyFieldOneToOneField を除くフィールドクラスは、 第一引数に表示用のフィールド名を指定できます。この引数は省略可能です。引数 を指定しない場合、 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 には、多対一 (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)
    # ...

再帰的リレーション (自分自身に対する多対多 のリレーション) や、 未定義のモデルに対するリレーション も定義できます。「 モデルフィールドのリファレン ス 」を参照してください。

必須ではありませんが、 ForeignKey の名前 (上の例では manufacturer) には、モデル名を小文字にしたものを使うよう勧 めます。もちろん、以下のように、好きな名前を付けてもかまいません:

class Car(models.Model):
    company_that_makes_it = models.ForeignKey(Manufacturer)
    # ...

See also

ForeignKey フィールドは モデルフィールドリファレンス で説明してい る多くの追加引数を受け取ります。これらのオプションはリレーションがどのよ うに動くべきかを定義するのに役立ちます。

逆参照されるオブジェクトへのアクセスについては リレーションの逆参照の例. に詳しく書いてあります。

多対多のリレーション

多対多の (many-to-many) リレーションを定義するには ManyToManyField を使います。このフィール ドは他のフィールド型と同じように、モデルのクラス属性に含めて使えます。

ManyToManyField には固定引数が一つあり、 リレーションを張る対象のクラスを指定します。

Pizza には複数の Topping オブジェクトを関連付ける例を考えてみましょ う。すなわち、ある Topping は複数のピザの上に置けて、逆にそれぞれのピザ には複数のトッピングを置けるというわけです。このリレーションを表現するには 以下のように定義します:

class Topping(models.Model):
    # ...

class Pizza(models.Model):
    # ...
    toppings = models.ManyToManyField(Topping)

ForeignKey と同様、 再帰的リレーション (自分自身に対する多対多のリレーション) や、 未定義のモデルに対するリレーション も定義できま す。「 モデルフィールドのリファレンス 」を参照して ください。

必須ではありませんが、 ManyToManyField の 名前 (上の例では toppings)は、リレーション先のモデル名の複数形にするよ う勧めます。

どちらのモデルで ManyToManyField を定義し てもかまいませんが、どちらか片方のモデルだけ指定すべきです – 両方には指定 すべきではありません。

一般的に言って、 Django の管理インタフェースを使うのなら、 ManyToManyField インスタンスを入れておく のは、管理インタフェースで編集される側のオブジェクトにしておくとよいでしょ う。上の例では、 topping は (ToppingManyToManyFieldpizzas をもたせる のではなく) Pizza に入れておきます。というのも、「トッピングを乗せるピ ザ」を編集するよりも「ピザの上に乗せるトッピング」を編集する方が自然だから です。というわけで、上の例のようにすれば、管理サイトの Pizza の編集画面 上でユーザにトッピングを選ばせられます。

See also

ManyToManyField フィールドも モデルフィールドリファレンス で説明して いる多くの引数を受け取ります。これらのオプションはリレーションがどの ように動くべきかを定義するのに役立ちます。必須ではありません。

エクストラフィールドで多対多を定義する

ピザとトッピングを組み合わせたり照合したりするだけのような多対多のリレーショ ンを扱いたいのなら、標準の ManyToManyField で事 足ります。しかし、時として、二つのモデルのリレーションそのものにデータを関 連づけたい場合があります。

例えば、ミュージシャンのグループと、在籍しているミュージシャンを追跡するア プリケーションのケースを考えてみましょう。これは個人 (person) とグループの 関係なので、 ManyToManyField でリレーションを表 現できるはずです。しかし、ミュージシャンとグループの関係には、あるミュージ シャンがあるグループにいつ合流したか、のような細かい情報がたくさんあります。

こうした状況に対応するために、Django には、あらかじめリレーションを管理する ためのモデル (中間モデル) を定義しておき、その中間モデルに向けてエクストラ フィールド (extra field) を組み込んで多対多のリレーションを定義する方法があ ります。中間モデルは ManyToManyFieldthrough 引数に指定します。ミュージシャン の例は以下のように書けます:

class Person(models.Model):
    name = models.CharField(max_length=128)

    def __unicode__(self):
        return self.name

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')

    def __unicode__(self):
        return self.name

class Membership(models.Model):
    person = models.ForeignKey(Person)
    group = models.ForeignKey(Group)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

中間モデルからは、多対多のリレーションの両側にあたるモデルに対して明示的に 外部キーを張らねばなりません。

中間モデルには、いくつか制約があります:

  • 中間モデルは、多対多リレーションのターゲットモデル (リレーションを張 られる側のモデル) に対する外部キーを 一つだけ しか定義できません (上の例では Person ですね)。同じモデルに複数の外部キーを定義する と、モデルのバリデーション時にエラーを送出します。
  • 中間モデルは、多対多リレーションのソースモデル (リレーションを張る側 のモデル) に対する外部キーを 一つだけ しか定義できません (上の例で は Group ですね)。同じモデルに複数の外部キーを定義すると、モデル のバリデーション時にエラーを送出します。
  • 自分自身に対する多対多のリレーションを定義するのに中間モデルを使う場 合にのみ、例外的に同じモデルに対するリレーションを二つ定義できます。 ただし、多対多リレーションの中では、二つの外部キーは別々、すなわちソー スとターゲットを区別して扱います。
  • 中間モデルを使って、あるモデルから自分自身に多対対のリレーションを定 義する場合、 symmetrical=False を指定せねばなりません (「 モデルフィールドのリファレンス 」を参照してください) 。

さて、これで中間モデル (例でいうところの Membership) を使った ManyToManyField を設定したので、多対多のリレーショ ンを生成できます。リレーションの生成は、中間モデルのインスタンス生成によっ て実現します:

>>> ringo = Person.objects.create(name="Ringo Starr")
>>> paul = Person.objects.create(name="Paul McCartney")
>>> beatles = Group.objects.create(name="The Beatles")
>>> m1 = Membership(person=ringo, group=beatles,
...     date_joined=date(1962, 8, 16),
...     invite_reason= "Needed a new drummer.")
>>> m1.save()
>>> beatles.members.all()
[<Person: Ringo Starr>]
>>> ringo.group_set.all()
[<Group: The Beatles>]
>>> m2 = Membership.objects.create(person=paul, group=beatles,
...     date_joined=date(1960, 8, 1),
...     invite_reason= "Wanted to form a band.")
>>> beatles.members.all()
[<Person: Ringo Starr>, <Person: Paul McCartney>]

通常の ManyToManyField と違って、 addcreate, (beatles.members = [...] のような) 代入では、リレーションの定義は行えま せん:

# 使えません。
>>> beatles.members.add(john)
# これも使えません。
>>> beatles.members.create(name="George Harrison")
# これもまた使えません。
>>> beatles.members = [john, paul, ringo, george]

なぜでしょうか。中間モデルでリレーションを作成するときには、単に PersonGroup の間のリレーションだけではなく、 Membership テーブルのレコー ドを生成するための情報が全て必要だからです。単に addcreate を呼 び出したり代入を行うだけでは、リレーション以外の情報を埋められません。その 結果、中間モデルを使う場合は、 addcreate は使えないのです。 中間モデルを使っている場合、多対多のリレーションを保存するには、中間モデル のインスタンスを生成するしかない、ということを覚えておいてください。

同じ理由で remove() メソッドも使えません。 ただし、 clear() メソッド を使えば、以下のように多対多のリレーションを一括して消去できます:

# ビートルズ解散
>>> beatles.members.clear()

ひとたび中間モデルによる多対多のリレーションを作成したら、通常の多対多リレー ションと同じように、リレーション先のモデルのアトリビュートを使ってリレーショ ンをまたいだクエリを実行できます:

# 'Paul' で始まる名前の人がメンバにいるグループを探す
>>> Groups.objects.filter(members__name__startswith='Paul')
[<Group: The Beatles>]

中間テーブルを使っているので、中間テーブルのアトリビュートを使ったクエリも 実行できます:

# 1961年1月1日以降に合流した Beatles のメンバを探す
>>> Person.objects.filter(
...     group__name='The Beatles',
...     membership__date_joined__gt=date(1961,1,1))
[<Person: Ringo Starr]

メンバの情報にアクセスする必要があれば、 Membership モデルのクエリを 直接実行することができます:

>>> ringos_membership = Membership.objects.get(group=beatles, person=ringo)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
u'Needed a new drummer.'

別の方法として、Person オブジェクトから 多対多の逆参照 クエリを使うことによって も同じ情報にアクセスできます。

>>> ringos_membership = ringo.membership_set.get(group=beatles)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
u'Needed a new drummer.'

一対一のリレーション

一対一のリレーションを定義するには、 OneToOneField を使います。このフィールド も他のフィールド型と同じように、モデルクラスのアトリビュートとして定義しま す。

このリレーションがもっとも有用なのは、あるオブジェクトが別のオブジェクトを 何らかの形で「拡張」している場合の主キーとして使う場合です。

OneToOneField には固定引数が一つあり、リ レーションを張る対象のクラスを指定します。

例えば、「場所 (place)」のデータベースを作るときには、アドレス、電話番号、 といった標準的なものを作成します。その上で、レストランデータベースを作成 するときに、 Restaurant モデルの中に同じフィールドをつくるような 繰り返し作業 (repeat yourself) をする代わりに、場所データベースを基盤にして レストランのデータベースを作成したいとしましょう。このとき、 Restaurant には Place への OneToOneField をもた せられます (レストランは場所に対して “is-a” の関係だからです。実際には、こ のような状況を扱うのに モデルの継承 を使いますが、 モデル継承は OneToOneField で実現されてい ます)。

ForeignKey と同様、 再帰的リレーション未定義のモデルに対するリレーション も定義できま す。詳しくは「 モデルフィールドのリファレンス 」を参 照してください。

See also

OneToOneField フィールドは、オプションの引数を一 つとります。引数は「 モデルフィールドリファレンス 」 で解説しています。

以前は、モデル中で OneToOneField を使うと、 そのフィールドは自動的にモデルの主キーになっていました。この仕様はもうなく なりましたが、主キーにしたければ手動で primary_key に指定できます。この 変更により、一つのモデル中で複数の OneToOneField を使えるようになりました。

ファイル間にまたがるモデル

あるモジュールから別のモジュールへのリレーションは全く問題なく張れます。リ レーションを張るには、以下の例のようにモデル定義の先頭でリレーション対称の モデルを import しておき、必要なところでそのモデルクラスを参照します:

from geography.models import ZipCode

class Restaurant(models.Model):
    # ...
    zip_code = models.ForeignKey(ZipCode)

フィールド名の制約

Django がモデルのフィールド名に課している制約は二つしかありません:

  1. フィールド名は Python の予約語であってはなりません。さもないと Python のシンタクスエラーを引き起こすからです。

    悪い例:

    class Example(models.Model):
        pass = models.IntegerField() # 'pass' は予約語です!
    
  2. フィールド名には二つ以上の連続するアンダースコアを入れてはなりません。 なぜなら、Django は二重アンダースコアをクエリ照合構文で使っているか らです。

    悪い例:

    class Example(models.Model):
        foo__bar = models.IntegerField() # 二重アンダースコアがあります!
    

データベースのカラム名はフィールドの名前と一致していなくてもよいので、デー タベース側では制約を回避できます。詳しくは後述の db_column を 参照してください。

joinwhere, select のような SQL の予約語を、モデルのフィール ド名に使っても かまいません 。というのも、Django は SQL クエリを生成する ときにデータベーステーブル名やカラム名を常にエスケープするからです。エスケー プにはデータベースエンジン固有のクオート方式を使います。

カスタムのフィールド型

既存のモデルフィールドが目的とするアプリケーションに合わない場合や、あまり 一般的でないデータベースカラムタイプを活用したい場合のために、独自のフィー ルドクラスを作成できます。カスタムフィールドの詳しい作成方法は 「 howto-custom-model-fields 」で説明しています。

Meta オプション

モデルにメタデータを指定するには、以下のようにモデルの内部クラス Meta を使います:

class Ox(models.Model):
    horn_length = models.IntegerField()

    class Meta:
        ordering = ["horn_length"]
        verbose_name_plural = "oxen"

モデルのメタデータとは、モデルインスタンスの整列順 (ordering)や、データベース上のテーブル名 (db_table)、モデル名の単数形や複数形 (verbose_name, verbose_name_plural) といっ た、「フィールドの情報でない」情報です。必須のメタデータはなく、 class Meta すら省略できます。

Meta に指定できるオプションの一覧は、「 モデルオプションのリファ レンス 」で解説しています。

モデルのメソッド

カスタムの行レベル (“row-level”) の機能をオブジェクトに実装するには、カスタ ムのメソッドを定義します。 Manager メソッドの目 的が「テーブル級 (table-wide)」 の操作であるのに対し、モデルメソッドは個々 のモデルインスタンス単位の操作を実現します。

モデルメソッドは、ビジネスロジックの置き場所をモデル一箇所に限定するための 効果的なテクニックです。

例えば、以下のモデルでは、いくつかカスタムメソッドを定義しています:

from django.contrib.localflavor.us.models import USStateField

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 = 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) です。

モデルインスタンスのリファレンス 」では、 各モデルに自動的に付与されるメソッド を全て 紹介しています。ほとんどのメソッドはオーバライド可能です。詳しくは後述の 既存のモデルメソッドをオーバライドする を参照してください。といっても、 たいていはせいぜい以下の 2 つのメソッドをオーバライドするぐらいで済むでしょ う:

__unicode__()

オブジェクトの「Unicode 表現」を返す、Python の「マジックメソッド」 です。 Python や Django はこのメソッドを使ってモデルインスタンスに 型強制を適用し、通常の文字列に変換したり表示したりしています。特に、 対話コンソールや管理インタフェース上でオブジェクトを表示するときに 使われています。

このメソッドは常に定義するよう勧めます。定義しておくと、いろいろと 便利だからです。

get_absolute_url()

このメソッドを定義しておくと、 Django にオブジェクトの URL を計算さ せられます。 Django の管理インタフェースなどで、オブジェクトに関連 した URL を特定するときにこのメソッドを使います。

オブジェクトを一意に特定できるような URL を持たせたいときには、この メソッドを定義しましょう。

既存のモデルメソッドをオーバライドする

他にも、データベースの動作をカプセル化していて、カスタマイズ可能な モ デルメソッド があります。特によく変更するのは、 save()delete() の動作でしょう。

こうしたモデルメソッドは、モデルオブジェクトの挙動を変えるために好きなだけ オーバライドできます。

組み込みメソッドをオーバライドする古典的なユースケースに、オブジェクトの保 存時に何か別の処理を行うというものがあります。例を示しましょう (save() のパラメタはドキュメントを参照してください。):

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def save(self, *args, **kwargs):
        do_something()
        super(Blog, self).save(*args, **kwargs) # 「実際の」 save() を呼び出します。
        do_something_else()

また、以下のようにすれば保存を抑止できます:

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def save(self, *args, **kwargs):
        if self.name == "Yoko Ono's blog":
            return # Yoko は自分のブログを持っていません!
        else:
            super(Blog, self).save(*args, **kwargs) # 「実際の」 save() を呼び出します。

スーパクラスのメソッド呼び出し、つまり super(Blog, self).save(*args, **kwargs) を忘れないでください。この呼び 出しを忘れると、デフォルトの処理が行われないため、データベースにデータが保 存されません。

*args, **kwargs によってモデルメソッドに渡せる引数をパススルーすること も重要です。 Django は時々ビルトインのモデルメソッドに新しい引数を追加して 拡張することがあります。メソッド定義で *args, **kwargs を使っておけば、 これらの引数が追加されても自動でサポートされることが保証されます。

削除のオーバーライド

QuerySet による一括オブジェクト削除 の時にはオブジェクトの delete() メソッドが呼ばれないこ とに注意してください。カスタマイズした削除ロジックが実行されることを 保証するには pre_deletepost_delete シグナルのいずれかまたは 両方を使えば良いでしょう。

カスタム SQL の実行

もう一つよくあるパターンは、カスタムの SQL 文をモデルメソッドやモジュールレ ベルのメソッドにに書くというものです。詳しくは、 「 素の SQL を扱う 」を参照してください。

モデルの継承

Django のモデルクラス継承は、 Python の通常のクラス継承とほぼ同じように動作 します。モデル継承を実現するには、一つだけきめておかねばならないことがあり ます。それは、親クラスを (独自のデータベーステーブルを持った) 独立のモデル にしたいか、親クラスを共通情報の単なるホルダとして使い、子クラスでその情報 を扱う形にしたいかです。

Django には 3 種類のモデル継承スタイルがあります。

  1. 複数の子モデルクラスでいちいち同じ情報を入力せずに済ませるために、親モ デルクラスに共通の情報を持たせたいことはよくあります。親モデルクラスを 単体で使うことがないのなら、 抽象ベースクラス を使うのがよ いでしょう。
  2. 一方、(他のアプリケーションなどにある) 既存のモデルをサブクラス化して拡 張したり、個々のモデルに固有のデータベースを持たせたいような場合には、 マルチテーブル継承 を使うのがよいでしょう。
  3. 親モデルクラスのフィールドには手を加えず、 Python レベルでの振る舞いだ けを変えたいのなら、 プロキシモデル を使うのがよいでしょう。

抽象ベースクラス

抽象ベースクラスは、たくさんのモデルに共通する情報を入れておきたいときに便 利な仕組みです。抽象ベースクラスを定義するには、ベースクラス定義の、 Metaabstract=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.get(id=12)
# p が Restaurant オブジェクトなら、子クラスを返す:
>>> p.restaurant
<Restaurant: ...>

ただし、上の pRestaurant クラスで ない のなら (Place から 直接生成されたオブジェクトや、他のクラスの親クラスなら) p.restaurant はエラーを引き起こします。

Meta とマルチテーブル継承

マルチテーブル継承では、子クラスが親クラスの Meta ク ラスを継承する意味がありません。 Meta オプションは全 て親クラスだけに適用されるべきもので、他のクラスに同じ内容を適用しても、矛 盾した振る舞いを引き起こすだけです(これは、独自のテーブルを持たない抽象ベー スクラスと対照的な部分です)。

従って、マルチテーブル継承の子クラスは親クラスの Meta クラスにアクセスする方法を持ちません。ただし、限られたケースで、子クラスが 親クラスの挙動を継承する場合があります。それは、子クラスで ordering または get_latest_by 属性を指定していない場合に、 親クラスの属性を継承するというものです。

親クラスで整列カラムが指定されていて、子クラス側で整列カラムを指定したくな い場合は、明示的設定を無効にしてください:

class ChildModel(ParentModel):
    ...
    class Meta:
        # 親クラスの整列カラム設定の効果を除去する
        ordering = []

継承と逆リレーション

マルチテーブル継承は親クラスと子クラスを暗黙の OneToOneField でリンクするので、前述の例のように、 親クラスから子クラスをたどれます。しかし、子クラスをたどるときに使う名前は、 ForeignKeyManyToManyField リレーションを定義したと きのデフォルトの related_name と同じ値 を使っています。従って、子クラスで ForeignKeyManyToManyField を別のクラスに向けて張る ときには、 必ず related_name をフ ィールドに指定せねばなりません。指定し忘れると、 Django は validatesyncdb 時にエラーを送出します。

例えば、上の Place クラスに対して、 ManyToManyField を持った別のサブクラスを定義する には、以下のように書きます:

class Supplier(Place):
    # Must specify related_name on all relations.
    customers = models.ManyToManyField(Restaurant, related_name='provider')

親クラスのリンクフィールドを定義する

すでに触れたように、 Django は子クラスと抽象クラスでない親クラスにリンクし た OneToOneField を自動的に生成します。親クラス へのリンク名を操作したければ、自分で OneToOneField を作成し、パラメタに parent_link=True を渡 してください。

プロキシモデル

マルチテーブル継承 を使う時には、各々のモ デルのサブクラスに新しくデータベーステーブルが作られます。サブクラスはデー タフィールドを追加して、親クラスにはない新しいデータを保存する箇所を増やす ので、これは一般的には望まれる動作です。

しかしながら、デフォルトのマネジャーを変えたり新しいメソッドを追加すること によって、同じモデルに対して Python の動作を変えたいだけのときがあります。 これが、プロキシモデル継承がある理由です。オリジナルのモデルに対して プロキシ を作ります。そうすれば、ただオリジナルのモデルを使用しているよ うに、プロキシモデルのインスタンスを作成、更新、削除して、全てのデータをセ ーブすることが出来ます。違いは、モデルの順序づけやデフォルトのマネジャーを オリジナルを改変せずに変更できるということです。

プロキシモデルは通常のモデルと同じように宣言します。 Django に対してそのモ デルがプロキシモデルであることを教えるためには、 Meta クラス内の proxy アトリビュートを True にします。

例えば、標準の User モデルに対してテ ンプレートの中で用いるメソッドを追加したい場合、このように定義します:

from django.contrib.auth.models import User

class MyUser(User):
    class Meta:
        proxy = True

    def do_something(self):
        ...

MyUser クラスは親である User クラ スと同じデータベーステーブル上で動作します。特に、 User のどんな新しいインスタンスでも、 MyUser を通してアクセスすることができます。逆も可能です:

>>> u = User.objects.create(username="foobar")
>>> MyUser.objects.get(username="foobar")
<MyUser: foobar>

また、モデルに別のデフォルトオーダーを定義する場合にもプロキシモデルを用い ることができます。標準の User モデル ではオーダーが定義されていません (ソートはコストがかかるので、ユーザを取得 する時にいつもそうしたくないため、故意にそうしています。) プロキシを使って いて、いつも username 属性で順序づけたい場合は、こうすると簡単です:

class OrderedUser(User):
    class Meta:
        ordering = ["username"]
        proxy = True

こうすると、普通の User のクエリでは 順序が定められていませんが OrderedUser のクエリは username で順序 づけられます。

クエリセットはリクエストされたモデルを返す

User オブジェクトへのクエリで Django に MyUser オブジェクトを返させることはできません。 User オブジェク トへのクエリセットは User 型のオブジェクトを返すでしょう。プロキシオブ ジェクトの全体的なポイントは、元の User に依存しているコードは元のモデ ルを使い、追加したコードは拡張を使えるということです。(他のどんなコードも 追加のコードに依存しません。) プロキシモデルは User (または他のどんな モデルも) を自分で作成したもので置き換える手段ではないのです。

親クラスの制限

プロキシモデルは抽象クラスでないモデルクラスを 1 つだけ継承しなくてはなり ません。抽象クラスでないモデルクラスの多重継承をすることはできません。プロ キシモデルは、異なるデータベーステーブルの行へのコネクションを提供していな いからです。プロキシモデルはモデルフィールドを定義して いない 抽象モデル クラスならばいくつでも継承することができます。

プロキシモデルは親の抽象モデルクラスから Meta オプションを継承します。

プロキシモデルマネジャー

もしプロキシモデルにモデルマネジャーを指定しなかった場合、マネジャーはモデ ルの親から継承します。もしマネジャーを定義すれば、それがデフォルトになりま す。それでも、親クラスに指定されたマネジャーを使用することも出来ます。

上述した例を続けましょう。User モデルに問い合わせる時使われるデフォル トのマネジャーを、このように変更することが出来ます:

class NewManager(models.Manager):
    ...

class MyUser(User):
    objects = NewManager()

    class Meta:
        proxy = True

もしプロキシに新しいマネジャーを加えたい場合、デフォルトで存在するものと置 き換えることなく、付け加えることができます。 custom manager のドキュメントで述 べているテクニックを使うことができます。 新しいマネジャーを含んだベースクラスを作成して、主なベースクラスの後にそれ を継承しています:

# Create an abstract class for the new manager.
class ExtraManagers(models.Model):
    secondary = NewManager()

    class Meta:
        abstract = True

class MyUser(User, ExtraManagers):
    class Meta:
        proxy = True

このテクニックを必要とすることはそんなにないでしょうが、可能です。

プロキシの継承とマネージされないモデルの違い

プロキシモデルの継承は、マネージされないモデルを作るのによく似ています。 マネージされないモデルは、モデルの Meta クラスに managed 属性を使うものです。 2 つの方法は全く同じものではないので、どちらを使った方がよいのか熟慮する 価値があります。

一つ目の違いは Meta.managed=False のモデルにはモデルフィールドを指定 できることです。 (そして実際、空のモデルを欲しいのでなければ、そうしなく てはいけませんね) 注意深く Meta.db_table を注意深く設定 することで、既存のモデルの影のような、しかし Python メソッドを追加する マネージされないモデルを作れます。しかしながら、それは新しく変更を加え る時に両方のコピーを同期させ続けなければならない脆弱なものになります。

もう 1 つの違いは、どのようにモデルのマネジャーが扱われるのかという、プ ロキシモデルにとってもっと大切な点です。プロキシモデルが意図しているの は、代理しているモデル自体のようにふるまうことです。だからデフォルトの マネジャーを含む親のモデルマネージャーを継承します。多テーブルのモデル を継承する場合、子は親からマネジャーを継承しません。エクストラフィールド が関係している場合は、カスタムマネジャーが適切であるとは限らないからです。 マネジャードキュメント にもっ と詳細な内容が載っています。

これら 2 つの特徴が実装されている時、これらを 1 つのオプションに押し込 めることが試みられました。そして継承の相互作用は一般的に、特にマネジャー は、 API をとても複雑にし、理解して使うことを難しくする可能性があると分 かりました。 2 つのオプションはあるケースでは必要だと分かりました。それ で、現在は 2 つのオプションが存在しています。

一般的なルールとして:

  1. 既存のモデルやデータベーステーブルをミラーしたくて、元のデータベース テーブルカラム全てを必要としない場合、 Meta.managed=False にして ください。このオプションはデータベースのビューとテーブルを Django の コントロール下に入れずにモデリングするのに役立ちます。
  2. Python でのみモデルの振る舞いを変えたいけれど、フィールドは同じものを 使いたい場合には Meta.proxy=True を使ってください。このように設定 すると、データがセーブされた時にプロキシモデルが元のモデルの構造を保 持したままの正確なコピーとなります。

多重継承

Python のサブクラスと同様、 Django のモデルも複数の親モデルクラスを継承でき ます。クラス内の名前解決には、 Python の通常の名前解決規則が適用されるので 注意してください。子クラスで特定の名前 (例えば Meta) を参照する場合、その名前を定義している最初のベースクラスの定義を使い、最初 に名前が見つかった時点で、それ以降同じ名前のオブジェクトの解決は行われませ ん。従って、複数の親クラスで別々に Meta クラスを定義 していても、最初のベースクラスの Meta だけが使われ、 それ以外は全て無視されます。

通常は、モデルの多重継承は必要ないでしょう。多重継承が便利なのは、主に特定 のフィールドやメソッドを追加するための ‘’mix-in’’ クラスを使う場合です。 継承の階層構造はできるだけ単純に、分かりやすくしておきましょう。さもないと、 子クラスで扱っている情報が、どの親クラスから来たか調べるために四苦八苦する はめになるでしょう。

フィールド名を「覆い隠すこと」は許可されていない

通常の Python クラスの継承では、子クラスで親クラスのどんな属性でもオーバラ イドすることができます。 Django では、 Field イ ンスタンスの属性は (少なくとも今のところは) オーバライドすることができませ ん。もし親クラスが author というフィールドを持っていたとして、親クラス を継承したどんなクラスの中でも新しく author フィールドを作ることはでき ません。

親モデルのフィールドをオーバライドすることは、インスタンスの初期化 (どのフ ィールドが Model.__init__ で初期化されるかを指定すること) 、そしてシリ アライズを困難なものにします。これらは通常の Python クラスの継承が全 く同じように扱う必要のない特徴です。つまり Django のモデル継承と Python ク ラスの継承との違いは決定的なものなのです。

この制限は Field インスタンスである属性のみに適 用されます。通常の Python 属性は望み通りにオーバーライドできます。また、こ の制限は Python が見ている属性の名前のみに適用されます。自身の手でデータベ ースのカラム名を指定するのなら、多テーブルの継承向けに同じカラム名を先祖と 子のクラス両方に登場させることもできます (二つの異なるデータベーステーブル のカラムとして)

先祖のモデルの中にあるモデルフィールドをオーバーライドしようとすると、 Django は FieldError を生じさせます。