モデル

モデルは、データに関する唯一かつ決定的な情報源です。あなたが保持するデータが必要とするフィールドとその動作を定義します。一般的に、各モデルは単一のデータベースのテーブルに対応付けられます。

基本:

  • モデルは各々 Python のクラスであり django.db.models.Model のサブクラスです。
  • モデルの属性はそれぞれがデータベースのフィールドを表します。
  • これら全てを用いて、Django はデータベースにアクセスする自動生成された API を提供します。 クエリを作成する を参照してください。

簡単な例

次の例では first_namelast_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 はこのモデルの フィールド です。各フィールドはクラスの属性として定義され、各属性はデータベースのカラムに関連付けられます。

上記の 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 というテーブル名は、いくつかのモデルのメタデータから自動的に生成されますがそれを無効化することができます。詳細は Table names を参照ください。
  • id フィールドは自動的に追加されますが、この処理を無効化することができます。自動インクリメントのプライマリーキーフィールド を参照ください。
  • この例における CREATE TABLE の SQL は PostgreSQL の文法に準拠していますが、Django は 設定ファイル 内に定義されたデータベースバックエンドに合わせた SQL を適切に生成してくれるということを覚えておくとよいでしょう。

モデルの利用

一度モデルを定義した後は、Django にこれらのモデルを 利用する ということを知らせる必要があります。そのためには、設定ファイルを編集して、設定値 INSTALLED_APPS に、定義した models.py を含むモジュール名を追加します。

たとえば、アプリケーションのモデルが myapp.models モジュール内に存在する場合 (このパッケージ構造は manage.py startapp スクリプトによってアプリケーション内に構築されるものです)、INSTALLED_APPS の部分を次のように定義します。

INSTALLED_APPS = [
    #...
    'myapp',
    #...
]

INSTALLED_APPS 内に新たなアプリケーションを追加した場合、manage.py migrate を、初回は必要に応じて manage.py makemigrations を忘れずに実行してください。

フィールド

モデルにおいて最も重要な箇所であり -- モデルにおいて唯一必須となっている箇所 -- それはそのモデルが定義するデータベースのフィールドの一覧です。フィールドはクラスの属性として定義されます。cleansave あるいは delete のようなフィールド名は、models API で利用されていて衝突してしまうため、選べないことに注意してください。

実装例:

from django.db import models

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, on_delete=models.CASCADE)
    name = models.CharField(max_length=100)
    release_date = models.DateField()
    num_stars = models.IntegerField()

フィールドの型

モデル内の各フィールドは適切に Field クラスのインスタンスとなっている必要があります。Django は、利用しているフィールドクラスの型に応じて以下のような挙動を決定します。

  • データベースに対して保存するデータのタイプを伝えるカラムの型です (例: INTEGERVARCHARTEXT)。
  • フォーム領域をレンダリングする際に利用するデフォルトの HTML ウィジェット (例えば <input type="text"><select>)。
  • 最低限必要とされる入力値確認、Django の管理機能と自動生成されるフォームにおいて利用されます。

Django は多くのフィールド型を内蔵しています; それらの完全な一覧は フィールドの型 で確認できます。もし Django に内蔵されたフィールドの型では実現できない機能を実装したい場合は独自のフィールドを簡単に記述できます; How to create custom model fields を参照してください。

フィールドオプション

フィールドはそれぞれあらかじめ定められたフィールド特有の引数 ( モデルのフィールド型一覧 にまとめられています) を受け取ります。例えば、CharField (およびそのサブクラス) はそのデータを保持するためにデータベース上に定義される VARCHAR 領域の長さを定義する引数 max_length を必要とします。

全てのフィールドの型で利用できる共通の引数も存在します。すべてオプションの引数です。これらの引数についてはこちらの リファレンス 内で全て説明されていますが、ここでは、特に頻繁に使われるものについて簡単な概要を説明します。

null
True の場合、Django はデータベース内に NULL として空の値を保持します。デフォルトは False です。
blank

True の場合、フィールドはブランクになることが許容されます。デフォルトは False です。

null とは挙動が異なる事に注意してください。 blank がバリデーション由来である一方、 null は完全にデータベース由来です。あるフィールドが blank=True であれば、フォームのバリデーションは空の値の入力を許容します。あるフィールドが blank=False の場合は、そのフィールドへの入力は必須となります。

choices

このフィールドを選択肢として使用するには、2タプルの sequence を使用します。デフォルトのフォームウィジェットが標準のテキストボックスではなくセレクトボックスになり、与えられた選択肢を選ぶように制限されます。

選択肢のリストは以下のようになります。

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

注釈

choices の順番を変更すると、変更のたびに新しいマイグレーションが生成されます。

各タプルの1番目の要素はデータベースに保存される値です。2番目の要素はフォームウィジェットに表示される名前です。

モデルのインスタンスが与えられたとき、choices のフィールドに対して表示される値は、get_FOO_display() メソッドを用いてアクセスすることができます。たとえば、次のようになります。

from django.db import models

class Person(models.Model):
    SHIRT_SIZES = (
        ('S', 'Small'),
        ('M', 'Medium'),
        ('L', 'Large'),
    )
    name = models.CharField(max_length=60)
    shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)
>>> p = Person(name="Fred Flintstone", shirt_size="L")
>>> p.save()
>>> p.shirt_size
'L'
>>> p.get_shirt_size_display()
'Large'

列挙型クラスを用いて、choices を簡潔に定義することもできます。

from django.db import models

class Runner(models.Model):
    MedalType = models.TextChoices('MedalType', 'GOLD SILVER BRONZE')
    name = models.CharField(max_length=60)
    medal = models.CharField(blank=True, choices=MedalType.choices, max_length=10)

もっと他の例は model field reference で見ることができます。

default
そのフィールドのデフォルト値です。このオプションには特定の値または呼び出し可能オブジェクトを渡すことができます。呼び出し可能オブジェクトの場合、新しくオブジェクトが生成される度に呼び出されます。
help_text
フォームウィジェットとともに表示される追加の「ヘルプ」テキストです。この値はフィールドがフォームとして利用されない場合でもドキュメントとして役に立ちます。
primary_key

True の場合、設定したフィールドはそのモデルの主キーとなります。

定義したモデル内でどのフィールドに対しても primary_key=True が設定されなかった場合、Django は自動的に主キーを保存するために IntegerField を追加します、つまりその主キーに対するデフォルトの動作を変更する必要がない場合はどのフィールドに対しても primary_key=True を設定する必要が有りません。詳細は 自動インクリメントのプライマリーキーフィールド を参照してください。

主キーとなったフィールドは読み込み専用となります。もし既存のオブジェクトの主キーの値を変更して保存する操作を行うと、既存のオブジェクトに加えて新たなオブジェクトが生成されます。以下に例を示します。

from django.db import models

class Fruit(models.Model):
    name = models.CharField(max_length=100, primary_key=True)
>>> fruit = Fruit.objects.create(name='Apple')
>>> fruit.name = 'Pear'
>>> fruit.save()
>>> Fruit.objects.values_list('name', flat=True)
<QuerySet ['Apple', 'Pear']>
unique
True の場合、そのフィールドはテーブル上で一意となる制約を受けます。

繰り返しになりますが、これらは特によく利用されるフィールドのオプションの概説です。完全な説明は 共通のフィールドオプションの説明 で参照できます。

自動インクリメントのプライマリーキーフィールド

By default, Django gives each model an auto-incrementing primary key with the type specified per app in AppConfig.default_auto_field or globally in the DEFAULT_AUTO_FIELD setting. For example:

id = models.BigAutoField(primary_key=True)

独自の主キーを設定したい場合は、いずれかのフィールドで primary_key=True を設定してください。そのようにして明示的に Field.primary_key が設定されている場合、Djangoは自動的に id カラムを追加しません。

各モデルには、primary_key=True が必ず 1 つだけ (明示的に宣言されるか、自動的に追加されるかのどちらかで) 存在する必要があります。

Changed in Django 3.2:

In older versions, auto-created primary key fields were always AutoFields.

詳細な (verbose) フィールド名

ForeignKeyManyToManyFieldOneToOneField の 3 つを除いた各フィールドは、任意の第 1 引数を取ります -- 詳細な (verbose) 名前です。詳細な名前を与えない場合、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)

ForeignKeyManyToManyFieldOneToOneField の 3 つは最初の引数にモデルクラスを必要とするので、verbose_name キーワード引数を使用してください:

poll = models.ForeignKey(
    Poll,
    on_delete=models.CASCADE,
    verbose_name="the related poll",
)
sites = models.ManyToManyField(Site, verbose_name="list of sites")
place = models.OneToOneField(
    Place,
    on_delete=models.CASCADE,
    verbose_name="related place",
)

慣習的に、verbose_name の最初の文字は大文字にしません。必要に応じて Django が自動的に変換します。

リレーション

リレーショナルデータベースの強力さがテーブル同士の関係によって決まることは疑いがありません。Dango では、最も一般的な 3 つのデータベースリレーションシップを定義しています: 多対 1、多対多、1 対 1 です。

多対一 (many-to-one) 関係

多対 1 の関係を定義するには、django.db.models.ForeignKey を使用してください。 使い方は他の Field 型と同じです: モデルのクラス属性として含めてください。

ForeignKey には位置引数が必要です: モデルと関係させるクラスです。

例えば、Car モデル Manufacturer を持っている -- そして Manufacturer は複数の car を作る一方で Car は 1 つしか Manufacturer を持たない -- 場合、以下の定義を使用してください:

from django.db import models

class Manufacturer(models.Model):
    # ...
    pass

class Car(models.Model):
    manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
    # ...

recursive relationships (自分自身に対する多対 1 の関係を持つオブジェクト) や relationships to models not yet defined を作成することもできます; 詳細は the model field reference を参照してください。

必須ではありませんが、ForeignKey フィールド名 (上記の例では manufacturer) はモデル名を小文字にしたものをおすすめします。もちろん、どんなフィールドでも呼び出すことができます。例えば、以下のようなフィールド名にすることも可能です。

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

参考

ForeignKey フィールドは多数の追加的な引数を受け入れます。これらは the model field reference にて説明しています。これらの引数は、リレーションシップがどのように動作すべきかを定義するのに役立ちます; すべて任意です。

逆向きに関係するオブジェクトへのアクセスの詳細については、下記の 逆向きの関係の例 を参照してください。

サンプルのコードは、Many-to-one relationship model example を参照してください。

多対多 (many-to-many) 関係

多対多の関係を定義するには、django.db.models.ManyToManyField を使用してください。 使い方は他の Field 型と同じです: モデルのクラス属性として含めてください。

ManyToManyField には位置引数が必要です: モデルと関係させるクラスです。

たとえば、Pizza が複数の Topping オブジェクトを持っている -- そして Topping は複数の pizza に載ることができ Pizza は複数の topping を持つ-- 場合、以下のように表現することができます:

from django.db import models

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

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

ForeignKey と同様に、recursive relationships (自分自身に対する多対 1 の関係を持つオブジェクト) や relationships to models not yet defined を作成することもできます。

必須ではありませんが、ManyToManyField フィールド (上記の例では toppings) は関係モデルオブジェクトの複数形が推奨されています。

どちらのフィールドに ManyToManyField を定義しても構いませんが、片方のフィールドのみに定義するようにしてください -- 両方ではありません。

一般的に、 ManyToManyField インスタンスは、フォームで編集されるオブジェクトの側にあります。上の例では、 toppingsPizza の中にあります ( ToppingpizzasManyToManyField を持つとするよりはそのほうがいいでしょう ) 。というのは、ピザが複数のトッピングを持つほうが、トッピングが複数のピザの上にあるというよりも自然だからです。このようにすることで、ユーザは `` Pizza`` フォームでトッピングを選ぶことができるようになります。

参考

完全な実装例は Many-to-many relationship model example を参照してください。

ManyToManyField フィールドは多数の追加的な引数を受け入れます。これらは the model field reference にて説明しています。これらの引数は、リレーションシップがどのように動作すべきかを定義するのに役立ちます; すべて任意です。

多対多リレーションにおける追加フィールド

ピザとトッピングを組み合わせる程度の多対多リレーションを扱うのであれば、標準の ManyToManyField で十分でしょう。しかし、2 つのモデルのリレーションに他のデータを付加したくなることもあります。

たとえば、ミュージシャンが所属する音楽グループを追跡するアプリについて考えてみましょう。ミュージシャンとグループの間には多対多の関係があるので、この関係を表すのに ManyToManyField が使えます。しかし、ある人がそのグループに加入した日などといった多くの詳細情報も集めたいとします。

このような場合、 Django ではそのような多対多リレーションを規定するのに使われるモデルを指定することができます。そうすることで、中間モデルに追加のフィールドを配置することができます。中間モデルは、 through 引数で中間として振る舞うモデルを指定することで、 ManyToManyField に紐付けることができます。ミュージシャンの例では、コードはこのようになるでしょう:

from django.db import models

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

    def __str__(self):
        return self.name

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

    def __str__(self):
        return self.name

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

中間モデルを指定する場合は、多対多リレーションに参加するモデルに対する外部キーを明示的に指定します。明示的に指定することで、ふたつのモデルがどのように関係するかが定義されます。

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

  • Your intermediate model must contain one - and only one - foreign key to the source model (this would be Group in our example), or you must explicitly specify the foreign keys Django should use for the relationship using ManyToManyField.through_fields. If you have more than one foreign key and through_fields is not specified, a validation error will be raised. A similar restriction applies to the foreign key to the target model (this would be Person in our example).
  • For a model which has a many-to-many relationship to itself through an intermediary model, two foreign keys to the same model are permitted, but they will be treated as the two (different) sides of the many-to-many relationship. If there are more than two foreign keys though, you must also specify through_fields as above, or a validation error will be raised.

Now that you have set up your ManyToManyField to use your intermediary model (Membership, in this case), you're ready to start creating some many-to-many relationships. You do this by creating instances of the intermediate model:

>>> 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()
<QuerySet [<Person: Ringo Starr>]>
>>> ringo.group_set.all()
<QuerySet [<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()
<QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>]>

You can also use add(), create(), or set() to create relationships, as long as you specify through_defaults for any required fields:

>>> beatles.members.add(john, through_defaults={'date_joined': date(1960, 8, 1)})
>>> beatles.members.create(name="George Harrison", through_defaults={'date_joined': date(1960, 8, 1)})
>>> beatles.members.set([john, paul, ringo, george], through_defaults={'date_joined': date(1960, 8, 1)})

You may prefer to create instances of the intermediate model directly.

If the custom through table defined by the intermediate model does not enforce uniqueness on the (model1, model2) pair, allowing multiple values, the remove() call will remove all intermediate model instances:

>>> Membership.objects.create(person=ringo, group=beatles,
...     date_joined=date(1968, 9, 4),
...     invite_reason="You've been gone for a month and we miss you.")
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>, <Person: Ringo Starr>]>
>>> # This deletes both of the intermediate model instances for Ringo Starr
>>> beatles.members.remove(ringo)
>>> beatles.members.all()
<QuerySet [<Person: Paul McCartney>]>

The clear() method can be used to remove all many-to-many relationships for an instance:

>>> # Beatles have broken up
>>> beatles.members.clear()
>>> # Note that this deletes the intermediate model instances
>>> Membership.objects.all()
<QuerySet []>

Once you have established the many-to-many relationships, you can issue queries. Just as with normal many-to-many relationships, you can query using the attributes of the many-to-many-related model:

# Find all the groups with a member whose name starts with 'Paul'
>>> Group.objects.filter(members__name__startswith='Paul')
<QuerySet [<Group: The Beatles>]>

As you are using an intermediate model, you can also query on its attributes:

# Find all the members of the Beatles that joined after 1 Jan 1961
>>> Person.objects.filter(
...     group__name='The Beatles',
...     membership__date_joined__gt=date(1961,1,1))
<QuerySet [<Person: Ringo Starr]>

If you need to access a membership's information you may do so by directly querying the Membership model:

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

Another way to access the same information is by querying the many-to-many reverse relationship from a Person object:

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

一対一 (one-to-one) 関係

1対1のリレーションを定義するには、OneToOneField を使用します。単純に他の Field 型と同じようにして、モデルのクラス属性に設定することができます。

あるオブジェクトが他のオブジェクトを何らかの方法で「拡張 (extends)」しているとき、オブジェクトの主キーに設定するのが最も便利です。

OneToOneField には1つの位置引数として、モデルと関係させるクラスを指定する必要があります。

For example, if you were building a database of "places", you would build pretty standard stuff such as address, phone number, etc. in the database. Then, if you wanted to build a database of restaurants on top of the places, instead of repeating yourself and replicating those fields in the Restaurant model, you could make Restaurant have a OneToOneField to Place (because a restaurant "is a" place; in fact, to handle this you'd typically use inheritance, which involves an implicit one-to-one relation).

As with ForeignKey, a recursive relationship can be defined and references to as-yet undefined models can be made.

参考

完全な実装例は、1対1リレーションモデルの例 を参照してください。

OneToOneField フィールドには、オプションの parent_link 引数を指定することもできます。

OneToOneField classes used to automatically become the primary key on a model. This is no longer true (although you can manually pass in the primary_key argument if you like). Thus, it's now possible to have multiple fields of type OneToOneField on a single model.

ファイルを横断したモデル

It's perfectly OK to relate a model to one from another app. To do this, import the related model at the top of the file where your model is defined. Then, refer to the other model class wherever needed. For example:

from django.db import models
from geography.models import ZipCode

class Restaurant(models.Model):
    # ...
    zip_code = models.ForeignKey(
        ZipCode,
        on_delete=models.SET_NULL,
        blank=True,
        null=True,
    )

フィールド名の制約

Django はモデルのフィールド名にいくつかの制約を課しています。

  1. フィールド名には Python の予約語が使えない。もし使用した場合、Python の構文エラーが起こります。たとえば、次のようになります。

    class Example(models.Model):
        pass = models.IntegerField() # 'pass' is a reserved word!
    
  2. フィールド名に2文字以上連続するアンダースコアを使用できない。これは、Django のクエリルックアップの構文のためです。たとえば、次のようになります。

    class Example(models.Model):
        foo__bar = models.IntegerField() # 'foo__bar' has two underscores!
    
  3. 同様の理由で、フィールド名の最後をアンダースコアにすることはできません。

しかし、これらの制約を回避する手段はあります。なぜなら、フィールド名は必ずしもデータベースのカラム名と一致する必要はないからです。詳細については db_column オプションをご覧ください。

ただし、joinwhereselect などの SQL の予約語はモデルのフィールド名に使用することができます。これは、Django がすべての SQL クエリに対して、データベースデーブル名とカラム名のエスケープを行っているためです。エスケープ処理では、使用しているデータベースエンジンのクオート構文を利用しています。

カスタムのフィールドタイプ

既存のモデルフィールドが目的に適わない場合、あるいは一般的ではないデータベースカラム型を利用したいと考えチエル場合、独自のフィールドクラスを作成することができます。自分自身のフィールドを作成する方法は、How to create custom model fields で提供しています。

Meta オプション

内側に class Meta というクラスを定義することで、モデルのメタデータを設定することができます。

from django.db import models

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

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

モデルのメタデータには「フィールド以外のすべての事項」が設定できます。例えば、並び替えオプション (ordering)、データベースのテーブル名 (db_table)、人が読むための単数形と複数形の名前 (verbose_nameverbose_name_plural) などです。必須のものはなく、class Meta のモデルへの追加は完全にオプションです。

Meta に指定できるオプションの完全なリストは、モデルオプションリファレンス で確認できます。

モデルの属性

objects
モデルの最も重要な属性は Manager です。これは、Django のモデルにデータベースクエリの操作を渡すインターフェースで、データベースから インスタンスを取り出す ために使われます。Manager が定義されていない場合、デフォルトの名前は objects となります。マネージャはモデルクラスを通じてのみアクセスできます。インスタンスからはアクセスできません。

モデルのメソッド

オブジェクトに独自の "行レベルの" 機能を追加するには、カスタムのメソッドを定義してください。Manager メソッドは "テーブル単位の" 操作をするように意図されており、モデルメソッドは特定のモデルインスタンス上で動作します。

これは、ビジネスロジックを 1 つの場所 -- モデルのことです -- で管理するための重要なテクニックです。

例えば、以下のモデルはいくつかのカスタムメソッドを持ちます:

from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    birth_date = models.DateField()

    def baby_boomer_status(self):
        "Returns the person's baby-boomer status."
        import datetime
        if self.birth_date < datetime.date(1945, 8, 1):
            return "Pre-boomer"
        elif self.birth_date < datetime.date(1965, 1, 1):
            return "Baby boomer"
        else:
            return "Post-boomer"

    @property
    def full_name(self):
        "Returns the person's full name."
        return '%s %s' % (self.first_name, self.last_name)

例にある最後のメソッドは property です。

model instance reference に、各モデルに自動的に与えられるメソッド の完全なリストがあります。 多くなオーバーライド可能です -- 後述の overriding predefined model methods を参照してください -- が、特によく定義することになるものがあります:

__str__()

Python の "魔法のメソッド" で、オブジェクトを表す文字列を返しま。 Python と Django は、モデルのインスタンスを文字列で表示する必要に迫られたときにこれを使います。特に、オブジェクトをインタラクティブコンソール内や admin 内で表示する際に該当します。

このメソッドは常に指定することを推奨します; デフォルトはあまり役に立つものではありません。

get_absolute_url()

Django にオブジェクトの URL の計算方法を定義します。Django はこのメソッドを admin インターフェイスで利用しており、オブジェクトの URL を使用する必要があるあらゆる場面でも使用されます。

ユニークに特定できる URL を持つすべてのオブジェクトには、このメソッドを定義しなければなりません。

定義済みのモデルメソッドをオーバーライドする

別の model methods セットを使って、多くのカスタマイズしたいデータベース動作をカプセル化できます。特に、save()delete() の動作を変更したいことがよくあります。

これらのメソッド (および他のすべてのメソッド) は自由にオーバーライドして、動作を変更することができます。

ビルトインのメソッドをオーバーライドする典型的な状況は、オブジェクトを保存するとき毎回何かを実行したい、という場合です。例えば (受け入れるパラメータについては save() を参照してください):

from django.db import models

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

    def save(self, *args, **kwargs):
        do_something()
        super().save(*args, **kwargs)  # Call the "real" save() method.
        do_something_else()

保存しないようにすることもできます:

from django.db import models

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 shall never have her own blog!
        else:
            super().save(*args, **kwargs)  # Call the "real" save() method.

スーパークラスのメソッドを呼び出し忘れないようにすることが重要です -- super().save(*args, **kwargs) のことです -- これでオブジェクトがデータベースに保存されることが保証されます。スーパークラスのメソッドを呼び出し忘れると、デフォルトの動作は発生せずデータベースは変更されません。

モデルのメソッドに引数を渡すこともまた重要です -- *args, **kwargs が行います。Django は、しばしばビルトインのモデルメソッドの機能を拡張するため、新しい引数を追加します。自分で記述したメソッド定義内に *args, **kwargs 使えば、新しい引数が追加しても自動的にサポートされるようになります。

オーバーライドされたモデルメソッドはバルク操作では呼ばれません

Note that the delete() method for an object is not necessarily called when deleting objects in bulk using a QuerySet or as a result of a cascading delete. To ensure customized delete logic gets executed, you can use pre_delete and/or post_delete signals.

Unfortunately, there isn't a workaround when creating or updating objects in bulk, since none of save(), pre_save, and post_save are called.

カスタムの SQL を実行する

その他のよくあるパターンとしては、カスタムの SQL 文をモデルのメソッドやモジュールのメソッドとして定義することがあります。生の SQL 文を使用する方法については、生の SQL を使用する を参照してください。

モデルの継承

Django におけるモデルの継承は Python における普通のクラスの継承とほぼ同じ方法で行われますが、最初の段階だけでもここで説明しておいた方がよいでしょう。それはその基底クラスが django.db.models.Model のサブクラスでなければならないという事です。

唯一決めるべきことは、親モデルを (保持するデータベースのテーブルと共に) 独自の権限を持ったモデルとするか、それとも子モデルを通じてのみ共通情報を参照する単なる保持者とするかです。

Django において可能な継承には 3 つの方式が有ります。

  1. 子モデルそれぞれに対して一々定義し直さないで済ませたい情報を保持するためだけに、親クラスを使用することがあるかもしれません。このクラスが単体で用いられることはないので、この場合 抽象基底クラス が適切です。
  2. もし既存のモデル (完全に別のアプリケーション等から取得した) のサブクラスを作成していてモデルそれぞれにデータベース上のテーブルを定義したい場合、 複数テーブルの継承 を利用するとよいでしょう。
  3. 最後に、モデルの Python レベルでの振る舞いを、モデルのフィールドを変更せずに修正したい場合は、 プロキシモデル を利用できます。

抽象基底クラス

抽象基底クラスは、複数の他モデルに対して共通の情報を入れ込みたいときに有用です。基底クラスを書いて Meta クラス内で abstract=True をセットしてください。これで、このモデルはデータベーステーブルを作成するために使用されることはなくなります。 代わりに、他のモデルで基底クラスとして使われる際に、これら子クラスのフィールドとして追加されます。

実装例:

from django.db import models

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 モデルは nameage そして home_group の 3 つのフィールドを持つことになります。 CommonInfo モデルは抽象基底クラスであるため、通常の Django モデルとしては利用できません。データベース上にテーブルを生成したりマネージャを持ったりせず、そしてインスタンス化されたり直接値を保存する事もできません。

抽象基底クラスを継承したフィールドは、他のフィールドや値でオーバーライドしたり、 None を使って削除することができます。

多くの場合、このタイプのモデル継承があなたの必要としているものでしょう。この方式では、データベースレベルでは子モデルごとのテーブルを 1 つずつ作る一方で、共通情報を Python レベルで因数分解できます。

Meta の継承

抽象基底クラスを作成した際、Django は基底クラスで宣言したすべての Meta インナークラスを子クラスの属性とします。子クラスが自身の Meta クラスを定義しなければ、親の Meta クラスを継承します。子クラスが親の Meta クラスを拡張したい場合、サブクラス化できます。例えば:

from django.db import models

class CommonInfo(models.Model):
    # ...
    class Meta:
        abstract = True
        ordering = ['name']

class Student(CommonInfo):
    # ...
    class Meta(CommonInfo.Meta):
        db_table = 'student_info'

Django does make one adjustment to the Meta class of an abstract base class: before installing the Meta attribute, it sets abstract=False. This means that children of abstract base classes don't automatically become abstract classes themselves. To make an abstract base class that inherits from another abstract base class, you need to explicitly set abstract=True on the child.

抽象基底クラスの Meta クラスに持っても意味をなさない属性がいくつか存在します。例えば、属性値 db_table を指定することは、子クラス (のうち自身の Meta を定義していないもの) が全て同じデータベース上のテーブルを利用することを意味しますが、これは明らかに必要なものではありません。

Due to the way Python inheritance works, if a child class inherits from multiple abstract base classes, only the Meta options from the first listed class will be inherited by default. To inherit Meta options from multiple abstract base classes, you must explicitly declare the Meta inheritance. For example:

from django.db import models

class CommonInfo(models.Model):
    name = models.CharField(max_length=100)
    age = models.PositiveIntegerField()

    class Meta:
        abstract = True
        ordering = ['name']

class Unmanaged(models.Model):
    class Meta:
        abstract = True
        managed = False

class Student(CommonInfo, Unmanaged):
    home_group = models.CharField(max_length=5)

    class Meta(CommonInfo.Meta, Unmanaged.Meta):
        pass

複数テーブルの継承

Django がサポートするもう一つのモデル継承は、ヒエラルキー内の各モデルすべてが、それ自体モデルであるような場合です。それぞれのモデルはデータベース上のテーブルに対応しており、個別にクエリーを作成したり、テーブルの作成ができます。継承の関係によって、(自動的に作成される OneToOneField を通して) 子モデルとその親モデルとの間にリンクが作られます。この継承を利用すると、たとえば、次のように書くことができます。

from django.db import models

class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)

class Restaurant(Place):
    serves_hot_dogs = models.BooleanField(default=False)
    serves_pizza = models.BooleanField(default=False)

データはデータベースの異なるテーブルに存在しますが、 Place のフィールドは全て Restaurant でも利用できます。以下は共に処理可能です:

>>> Place.objects.filter(name="Bob's Cafe")
>>> Restaurant.objects.filter(name="Bob's Cafe")

もし、Restaurant でもある Place が存在する時、小文字にしたモデル名を使うことで、Place オブジェクトから Restaurant オブジェクトを取得できます。

>>> p = Place.objects.get(id=12)
# If p is a Restaurant object, this will give the child class:
>>> p.restaurant
<Restaurant: ...>

しかし、上の例において pRestaurant オブジェクト ではない 場合 (つまり、継承を用いず Place オブジェクトが直接作成されたもしくは他のクラスの親であった場合)、p.restaurant を参照すると、Restaurant.DoesNotExist 例外が発生します。

Place にリンクする Restaurant 上に自動的に生成された OneToOneField は、次のようなものになります。

place_ptr = models.OneToOneField(
    Place, on_delete=models.CASCADE,
    parent_link=True,
    primary_key=True,
)

Restaurant 上で、自分自身の OneToOneFieldparent_link=True を付けて宣言すれば、このフィールドをオーバーライドできます。

Meta と複数テーブルの継承

複数のテーブルを継承する状況では、子クラスにとって親クラスの Meta クラスを継承する事には意味が有りません。全ての Meta オプションは既に親クラスにおいて適用されておりそれを再度定義する事は矛盾した挙動を示すことに繋がります(これは基礎となるクラスの存在を当然の機能としては期待できない抽象基底クラスと対照的です)。

そのため子モデルは親モデルの Meta クラスへのアクセスを持ちません。しかし、限られた状況において子モデルが親モデルから挙動を継承する場合が有ります:もし子モデルが ordering 属性もしくは get_latest_by 属性を設定しなかった場合、これらを親モデルから継承します。

もし親モデルが ordering 属性を持っており子モデルに既定のデータ並び順を持たせたくない場合、明示的に無効化する事ができます:

class ChildModel(ParentModel):
    # ...
    class Meta:
        # Remove parent's ordering effect
        ordering = []

継承と関係の逆引き

複数テーブルの継承は親モデルと子モデルの関連付けに暗黙的な OneToOneField を利用するため、先の例で示されたように、親から子に情報を移動させることは可能です。しかしその関連付けには ForeignKey および ManyToManyField に付与されたデフォルトの related_name の値を利用します。もしこの種類の関連付けを親モデルのサブクラスに対して用いる場合、 related_name 属性を各フィールドに 定義しなければなりません 。もし設定を忘れれば、Django はバリデーション例外を送出します。

例として、上で用いた Place クラスを再度用いて、また別のサブクラスを ManyToManyField によって作成してみましょう:

class Supplier(Place):
    customers = models.ManyToManyField(Place)

この処理の結果はエラーとなります:

Reverse query name for 'Supplier.customers' clashes with reverse query
name for 'Supplier.place_ptr'.

HINT: Add or change a related_name argument to the definition for
'Supplier.customers' or 'Supplier.place_ptr'.

customers フィールドに related_name を追加する事でこのエラーを解消できます: models.ManyToManyField(Place, related_name='provider')

プロキシモデル

複数テーブルの継承 を利用しているとき、あるモデルのサブクラス毎に新たなデータベースのテーブルが作成されます。これは基底クラスに存在しない追加のデータフィールドをサブクラスが保存する場所が必要なため、通常必要とされる動作です。しかしながら、モデルの Python 上の振る舞いを変更したい事も有ります -- デフォルトのマネージャーを変更したり、新たなメソッドを追加したりする場合です。

プロキシモデルによる継承が利用できるのはこういった状況です:オリジナルのモデルのための プロキシ を作るのです。プロキシモデルで通してインスタンスを作成、削除、更新して (プロキシされない) オリジナルのモデルを利用しているかのようにデータを保存できます。プロキシを利用した場合に生じる違いは、オリジナルのモデルに変更を加えることなく、デフォルトのモデルのソート順やマネージャーの設定をプロキシ上で変更できるという点です。

プロキシモデルは通常のモデルと同様に定義されます。Django にそれがプロキシモデルである事を伝えるには Meta クラスの proxy 属性値を True にします。

例として、Person モデルにメソッドを追加すると仮定します。以下のように記述することで実現できます:

from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

class MyPerson(Person):
    class Meta:
        proxy = True

    def do_something(self):
        # ...
        pass

MyPerson クラスはその親である Person クラス同様に同じデータベースのテーブルを操作しています。特に、Person の新たなインスタンスは全て MyPerson を通じてアクセス可能であり、逆も同様です:

>>> p = Person.objects.create(first_name="foobar")
>>> MyPerson.objects.get(first_name="foobar")
<MyPerson: foobar>

You could also use a proxy model to define a different default ordering on a model. You might not always want to order the Person model, but regularly order by the last_name attribute when you use the proxy:

class OrderedPerson(Person):
    class Meta:
        ordering = ["last_name"]
        proxy = True

これで通常の Person に対する問い合わせでは特に結果は並び替えられず OrderedPerson に対する問い合わせでは last_name に基づいて並び替えられます。

プロキシモデルは Meta の属性値を 通常のモデルと同様に 継承します。

QuerySets はリクエストされたモデルを返し続ける

Person オブジェクトに対して問い合わせた場合に Django に、あえて言えば、 MyPerson オブジェクトを返させる事はできません。プロキシオブジェクトのポイントはオリジナルの Person に依存しているコードはそちらを使いつつ、新たに含んだ (他のコードがどんな形であれ依存しない) 拡張を使うコードを書けるという点です。 Person モデル (や他の全てのモデル) を新たに作った何物かに置き換える方法ではありません。

基底クラスの制限

プロキシモデルは厳格に一つの抽象的でないモデルクラスを継承しなければなりません。複数の非抽象クラスを、異なるデータベースのテーブル上の列と列を接続しない、プロキシモデルとして継承する事はできません。プロキシモデルは、いかなるモデルのフィールドも定義 しない 、抽象モデルクラスをいくらでも継承できます。プロキシモデルはまた共通の非抽象な親クラスを持つプロキシモデルをいくらでも継承できます。

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

プロキシモデル上にモデルのマネージャーを定義しない場合、そのプロキシモデルはマネージャーを親のモデルから継承します。プロキシモデル上にマネージャーを定義する場合、親クラス上のマネージャーで定義されて利用可能な物が有ったとしても、そのマネージャーがデフォルトになります。

前節の例を使うと、 Person モデルに問い合わせる場合は以下のようにデフォルトマネージャーを変更して用いることができます:

from django.db import models

class NewManager(models.Manager):
    # ...
    pass

class MyPerson(Person):
    objects = NewManager()

    class Meta:
        proxy = True

既存の物を置き換えることなく、プロキシモデルに新たなマネージャーを追加したい場合は、 カスタムマネージャー の説明に記述されたテクニックを用いることができます: 新たに実装したマネージャーを含んだ基底クラスを作成し、これを元々の基底クラスに続けて多重継承してください:

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

    class Meta:
        abstract = True

class MyPerson(Person, ExtraManagers):
    class Meta:
        proxy = True

上記の操作が頻繁に必要となる事は無いでしょうが、このような実装も可能なのです。

プロキシモデルの継承と管理対象外モデルの違い

プロキシモデルの継承は、あるモデルの Meta クラスにおける managed 属性を用いて Django に管理されないモデルを作成するのにかなり似ています。

Meta.db_table を入念に設定する事で既に存在するモデルとそれに対応する Python メソッドを隠ぺいする管理対象外モデルを作成できます。しかしながら、この操作は変更を加えた際に定義を複製して同期する際にとても冗長で変更に弱い物となります。

一方、プロキシモデルはプロキシするモデルと全く同じように振る舞うことを企図しています。それらのモデルは直接フィールドとマネージャーを継承しているため、常に親モデルに同期しています。

原則としては:

  1. もし既存のモデルやデータベースのテーブルを反映したいが元となるテーブルのカラムの全てを必要とする訳ではない場合は、 Meta.managed=False を利用してください。このオプションはデータベースのビューやテーブルを Django の管理下に置きたくない場合に通常有用となります。
  2. もしあるモデルの Python の箇所の振る舞いだけを変更したいが、元となるモデルと同じフィールドを保持したい場合は Meta.proxy=True を使用してください。この設定はデータ保存時にプロキシモデルが、元となるモデル側の保管構造の完全な複製となるように諸々を設定します。

多重継承

Python におけるサブクラス化と同様に、 Django のモデルは複数の親モデルを継承する事ができます。Python で通常用いられる名前解決の規則が適用されることを念頭に置いてください。特定の名称のオブジェクト (例えば Meta 等) を内部に最初に持って定義された基底クラスのそのオブジェクトが利用されます;例えば、複数の親モデルが Meta クラスを持っていた場合、最初に定義されたモデルのクラスが利用され、それ以外は無視されます。

通常は複数の親モデルを継承する必要はありません。この機能が有用な主な状況はクラスの "ミックスイン" 、ミックスイン用クラスを継承する全てのクラスに特別なフィールドやメソッドを追加させる技術、を利用する場合です。情報の特定の箇所がどこに由来するか突き止めるため奮闘しなくて済むように、継承の依存関係を可能な限り簡単で直観的な状態で維持するようにして下さい。

共通の id 主キーフィールドを持った複数のモデルを継承すると例外が送出されることに注意してください。多重継承を正常に使うために、基底モデル内で明示的に AutoField を利用できます。

class Article(models.Model):
    article_id = models.AutoField(primary_key=True)
    ...

class Book(models.Model):
    book_id = models.AutoField(primary_key=True)
    ...

class BookReview(Book, Article):
    pass

Or use a common ancestor to hold the AutoField. This requires using an explicit OneToOneField from each parent model to the common ancestor to avoid a clash between the fields that are automatically generated and inherited by the child:

class Piece(models.Model):
    pass

class Article(Piece):
    article_piece = models.OneToOneField(Piece, on_delete=models.CASCADE, parent_link=True)
    ...

class Book(Piece):
    book_piece = models.OneToOneField(Piece, on_delete=models.CASCADE, parent_link=True)
    ...

class BookReview(Book, Article):
    pass

フィールド名の "隠ぺい" は許可されない

通常の Python のクラス継承では、親クラスから継承したあらゆる属性を子クラスがオーバーライドできます。Django では、この挙動は通常モデルのフィールドに対して許容されません。もし非抽象なモデルの基底クラスが author フィールドを持っていたとしたら、そのモデルの基底クラスを継承したあらゆるモデルクラス内では author という名称の属性値を別のモデルのフィールドや属性として定義できなくなります。

この制約は抽象モデルを継承したモデルのフィールドに対しては適用されません。こういったフィールドは別のフィールドや値によってオーバーライドされるか field_name = None を設定することで削除する事ができます:

警告

モデルマネージャーは抽象基底クラスより継承されます。継承された Manager から参照される継承されたフィールドをオーバーライドするとちょっとしたバグを発生させる事が有ります。詳細は カスタムマネージャーとモデルの継承 を参照ください。

注釈

ある種のフィールドはモデル上に特別な属性を定義します、例えば ForeignKey_id がフィールド名に付与された属性を、外部モデル上の related_namerelated_query_name と同じように定義します。

これらの特別な属性はその属性を定義しているフィールドが、もはやその特別な属性を定義しなくなるように、変更もしくは削除されなければオーバーライドできません。

親モデルのフィールドをオーバーライドする事はインスタンス (どのフィールドが初期化されるか Model.__init__ に定義している) の初期化やシリアライズ時の問題につながります。これらは通常の Python のクラス継承で全く同様に扱う事が求められていない機能であるため、 Django のモデル継承と Python のクラス継承のこうした差異は恣意的な設計による物ではありません。

この制限は Field のインスタンスである属性に対してのみ適用されます。通常の Python の属性は望むままにオーバーライドできます。またその制約は Python が解析する際の属性の名称にのみ影響します:もしデータベースのカラム名を手動で設定したい場合、複数テーブルの継承 (2 つの異なるデータベースのテーブルに保持されているカラム) を表現する際に子と祖先のモデルで同じカラム名を設定できます。

もし祖先モデルのいずれかに定義されたモデルのフィールドをオーバーライドした場合 Django は FieldError 例外を送出します。

Note that because of the way fields are resolved during class definition, model fields inherited from multiple abstract parent models are resolved in a strict depth-first order. This contrasts with standard Python MRO, which is resolved breadth-first in cases of diamond shaped inheritance. This difference only affects complex model hierarchies, which (as per the advice above) you should try to avoid.

パッケージ化したモデルを扱う

manage.py startapp コマンドを実行することで models.py ファイルを含むアプリケーション構造が作成されます。多数のモデルが存在する場合、それらを別のファイルとして管理するのが良いかもしれません。

それを行うため、 models パッケージを作成します。 models.py を削除してモデルを保持するための __init__.py ファイルを持つ myapp/models/ ディレクトリを作成します。作成した __init__.py でモデルをインポートする必要が有ります。

例えば、 organic.py および synthetic.pymodels ディレクトリ内に持っている場合:

myapp/models/__init__.py
from .organic import Person
from .synthetic import Robot

from .models import * という記述を用いずに各モデルを明示的にインポートする方法には名前空間を汚染しない、可読性を向上させる、コード解析ツールを有用な状態に保つという利点が有ります。

参考

モデルの手引き
モデルのフィールド、関連オブジェクト、QuerySet を含む、モデルに関係するすべての API について説明しています。
Back to Top