モデル¶
モデルは、データに関する単一の決定的な情報源です。これはあなたが保持するデータが必要とするフィールドと振る舞いについての情報を持ちます。一般的に、各モデルは単一のデータベースのテーブルに対応付けられます。
基本:
- モデルは各々 Python のクラスであり
django.db.models.Model
のサブクラスです。 - モデルの属性はそれぞれがデータベースのフィールドを表します。
- これら全てを用いて、Django はデータベースにアクセスする自動生成された 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_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
フィールドは自動的に追加されますが、この処理を無効化する事ができます。Automatic primary key fields を参照ください。- この例における
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
を忘れずに実行してください。
フィールド¶
モデルにおいて最も重要な箇所であり – モデルにおいて唯一必須となっている箇所 – それはそのモデルが定義するデータベースのフィールドの一覧になります。フィールドはクラスの属性として定義されます。フィールド名として clean
、save
あるいは 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 は利用しているフィールドクラスの型に応じて以下のような挙動を決定します:
- カラムの型、データベースに保持するデータがどのような種別の物であるかを表します(例えば
INTEGER
、VARCHAR
、TEXT
等です)。 - フォーム領域をレンダリングする際に利用するデフォルトの HTML ウィジェット (例えば
<input type="text">
、<select>
)。 - 最低限必要とされる入力値確認、Django の管理機能と自動生成されるフォームにおいて利用されます。
Django は多くのフィールド型を内蔵しています; それらの完全な一覧は フィールドの型 で確認できます。もし Django に内蔵されたフィールドの型では実現できない機能を実装したい場合は独自のフィールドを簡単に記述できます; Writing custom model fields を参照してください。
フィールドオプション¶
フィールドはそれぞれあらかじめ定められたフィールド特有の引数 ( モデルのフィールド型一覧 にまとめられています) を受け取ります。例えば、CharField
(およびそのサブクラス) はそのデータを保持するためにデータベース上に定義される VARCHAR
領域の長さを定義する引数 max_length
を必要とします。
これらに加えてまた全てのフィールドの型で利用できる共通の引数が存在します。これらは全て入力が任意の物です。これらの引数についてはこちらの リファレンス 内で全て説明されていますが、ここにはそれらの内特に頻繁に用いられるものに関する概説を記述します:
null
True``の場合、Django はデータベース内に ``NULL
として空の値を保持します。デフォルトはFalse
です。blank
True
の場合、フィールドはブランクになることが許容されます。デフォルトはFalse
です。null
とは挙動が異なる事に注意してください。blank
がバリデーション由来である一方、null
は完全にデータベース由来です。あるフィールドがblank=True
であれば、フォームのバリデーションは空の値の入力を許容します。あるフィールドがblank=False
の場合は、そのフィールドへの入力は必須となります。choices
フィールドの選択肢として用いられる 2 値のタプルのイテラブルなオブジェクト (例えばリストやタプル) です。このオプションが渡された場合、デフォルトのフォームウィジェットが標準のテキストフィールドからセレクトボックスに変わり与えられた選択肢のみに選択を制限します。
選択肢のリストは以下のようになります:
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): 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'
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
の場合、そのフィールドはテーブル上で一意となる制約を受けます。
繰り返しになりますが、これらは特によく利用されるフィールドのオプションの概説です。完全な説明は 共通のフィールドオプションの説明 で参照できます。
Automatic primary key fields¶
By default, Django gives each model the following field:
id = models.AutoField(primary_key=True)
This is an auto-incrementing primary key.
If you’d like to specify a custom primary key, just specify
primary_key=True
on one of your fields. If Django
sees you’ve explicitly set Field.primary_key
, it won’t add the automatic
id
column.
Each model requires exactly one field to have primary_key=True
(either explicitly declared or automatically added).
Verbose field names¶
Each field type, except for ForeignKey
,
ManyToManyField
and
OneToOneField
, takes an optional first positional
argument – a verbose name. If the verbose name isn’t given, Django will
automatically create it using the field’s attribute name, converting underscores
to spaces.
In this example, the verbose name is "person's first name"
:
first_name = models.CharField("person's first name", max_length=30)
In this example, the verbose name is "first name"
:
first_name = models.CharField(max_length=30)
ForeignKey
,
ManyToManyField
and
OneToOneField
require the first argument to be a
model class, so use the verbose_name
keyword argument:
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",
)
The convention is not to capitalize the first letter of the
verbose_name
. Django will automatically capitalize the first
letter where it needs to.
Relationships¶
Clearly, the power of relational databases lies in relating tables to each other. Django offers ways to define the three most common types of database relationships: many-to-one, many-to-many and one-to-one.
Many-to-one relationships¶
To define a many-to-one relationship, use django.db.models.ForeignKey
.
You use it just like any other Field
type: by
including it as a class attribute of your model.
ForeignKey
requires a positional argument: the class
to which the model is related.
For example, if a Car
model has a Manufacturer
– that is, a
Manufacturer
makes multiple cars but each Car
only has one
Manufacturer
– use the following definitions:
from django.db import models
class Manufacturer(models.Model):
# ...
pass
class Car(models.Model):
manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
# ...
You can also create recursive relationships (an object with a many-to-one relationship to itself) and relationships to models not yet defined; see the model field reference for details.
It’s suggested, but not required, that the name of a
ForeignKey
field (manufacturer
in the example
above) be the name of the model, lowercase. You can, of course, call the field
whatever you want. For example:
class Car(models.Model):
company_that_makes_it = models.ForeignKey(
Manufacturer,
on_delete=models.CASCADE,
)
# ...
参考
ForeignKey
fields accept a number of extra
arguments which are explained in the model field reference. These options help define how the relationship
should work; all are optional.
For details on accessing backwards-related objects, see the Following relationships backward example.
For sample code, see the Many-to-one relationship model example.
Many-to-many relationships¶
To define a many-to-many relationship, use
ManyToManyField
. You use it just like any other
Field
type: by including it as a class attribute of
your model.
ManyToManyField
requires a positional argument: the
class to which the model is related.
For example, if a Pizza
has multiple Topping
objects – that is, a
Topping
can be on multiple pizzas and each Pizza
has multiple toppings
– here’s how you’d represent that:
from django.db import models
class Topping(models.Model):
# ...
pass
class Pizza(models.Model):
# ...
toppings = models.ManyToManyField(Topping)
As with ForeignKey
, you can also create
recursive relationships (an object with a
many-to-many relationship to itself) and relationships to models not yet
defined.
It’s suggested, but not required, that the name of a
ManyToManyField
(toppings
in the example above)
be a plural describing the set of related model objects.
It doesn’t matter which model has the
ManyToManyField
, but you should only put it in one
of the models – not both.
Generally, ManyToManyField
instances should go in
the object that’s going to be edited on a form. In the above example,
toppings
is in Pizza
(rather than Topping
having a pizzas
ManyToManyField
) because it’s more natural to think
about a pizza having toppings than a topping being on multiple pizzas. The way
it’s set up above, the Pizza
form would let users select the toppings.
参考
See the Many-to-many relationship model example for a full example.
ManyToManyField
fields also accept a number of
extra arguments which are explained in the model field reference. These options help define how the relationship
should work; all are optional.
Extra fields on many-to-many relationships¶
When you’re only dealing with simple many-to-many relationships such as
mixing and matching pizzas and toppings, a standard
ManyToManyField
is all you need. However, sometimes
you may need to associate data with the relationship between two models.
For example, consider the case of an application tracking the musical groups
which musicians belong to. There is a many-to-many relationship between a person
and the groups of which they are a member, so you could use a
ManyToManyField
to represent this relationship.
However, there is a lot of detail about the membership that you might want to
collect, such as the date at which the person joined the group.
For these situations, Django allows you to specify the model that will be used
to govern the many-to-many relationship. You can then put extra fields on the
intermediate model. The intermediate model is associated with the
ManyToManyField
using the
through
argument to point to the model
that will act as an intermediary. For our musician example, the code would look
something like this:
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self): # __unicode__ on Python 2
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __str__(self): # __unicode__ on Python 2
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)
When you set up the intermediary model, you explicitly specify foreign keys to the models that are involved in the many-to-many relationship. This explicit declaration defines how the two models are related.
There are a few restrictions on the intermediate model:
- 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 usingManyToManyField.through_fields
. If you have more than one foreign key andthrough_fields
is not specified, a validation error will be raised. A similar restriction applies to the foreign key to the target model (this would bePerson
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. - When defining a many-to-many relationship from a model to
itself, using an intermediary model, you must use
symmetrical=False
(see the model field reference).
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>]>
Unlike normal many-to-many fields, you can’t use add()
, create()
,
or set()
to create relationships:
>>> # The following statements will not work
>>> beatles.members.add(john)
>>> beatles.members.create(name="George Harrison")
>>> beatles.members.set([john, paul, ringo, george])
Why? You can’t just create a relationship between a Person
and a Group
- you need to specify all the detail for the relationship required by the
Membership
model. The simple add
, create
and assignment calls
don’t provide a way to specify this extra detail. As a result, they are
disabled for many-to-many relationships that use an intermediate model.
The only way to create this type of relationship is to create instances of the
intermediate model.
The remove()
method is
disabled for similar reasons. For example, if the custom through table defined
by the intermediate model does not enforce uniqueness on the
(model1, model2)
pair, a remove()
call would not provide enough
information as to which intermediate model instance should be deleted:
>>> 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 will not work because it cannot tell which membership to remove
>>> beatles.members.remove(ringo)
However, 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 by creating instances of your intermediate model, 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 relationships¶
To define a one-to-one relationship, use
OneToOneField
. You use it just like any other
Field
type: by including it as a class attribute of your model.
This is most useful on the primary key of an object when that object 「extends」 another object in some way.
OneToOneField
requires a positional argument: the
class to which the model is related.
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.
参考
See the One-to-one relationship model example for a full example.
OneToOneField
fields also accept an optional
parent_link
argument.
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.
Models across files¶
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, just 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,
)
Field name restrictions¶
Django places only two restrictions on model field names:
A field name cannot be a Python reserved word, because that would result in a Python syntax error. For example:
class Example(models.Model): pass = models.IntegerField() # 'pass' is a reserved word!
A field name cannot contain more than one underscore in a row, due to the way Django’s query lookup syntax works. For example:
class Example(models.Model): foo__bar = models.IntegerField() # 'foo__bar' has two underscores!
These limitations can be worked around, though, because your field name doesn’t
necessarily have to match your database column name. See the
db_column
option.
SQL reserved words, such as join
, where
or select
, are allowed as
model field names, because Django escapes all database table names and column
names in every underlying SQL query. It uses the quoting syntax of your
particular database engine.
Custom field types¶
If one of the existing model fields cannot be used to fit your purposes, or if you wish to take advantage of some less common database column types, you can create your own field class. Full coverage of creating your own fields is provided in Writing custom model fields.
Meta
options¶
Give your model metadata by using an inner class Meta
, like so:
from django.db import models
class Ox(models.Model):
horn_length = models.IntegerField()
class Meta:
ordering = ["horn_length"]
verbose_name_plural = "oxen"
Model metadata is 「anything that’s not a field」, such as ordering options
(ordering
), database table name (db_table
), or
human-readable singular and plural names (verbose_name
and
verbose_name_plural
). None are required, and adding class
Meta
to a model is completely optional.
A complete list of all possible Meta
options can be found in the model
option reference.
Model attributes¶
objects
- The most important attribute of a model is the
Manager
. It’s the interface through which database query operations are provided to Django models and is used to retrieve the instances from the database. If no customManager
is defined, the default name isobjects
. Managers are only accessible via model classes, not the model instances.
Model methods¶
Define custom methods on a model to add custom 「row-level」 functionality to your
objects. Whereas Manager
methods are intended to do
「table-wide」 things, model methods should act on a particular model instance.
This is a valuable technique for keeping business logic in one place – the model.
For example, this model has a few custom methods:
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)
The last method in this example is a property.
The model instance reference has a complete list of methods automatically given to each model. You can override most of these – see overriding predefined model methods, below – but there are a couple that you’ll almost always want to define:
__str__()
(Python 3)A Python 「magic method」 that returns a unicode 「representation」 of any object. This is what Python and Django will use whenever a model instance needs to be coerced and displayed as a plain string. Most notably, this happens when you display an object in an interactive console or in the admin.
You’ll always want to define this method; the default isn’t very helpful at all.
__unicode__()
(Python 2)- Python 2 equivalent of
__str__()
. get_absolute_url()
This tells Django how to calculate the URL for an object. Django uses this in its admin interface, and any time it needs to figure out a URL for an object.
Any object that has a URL that uniquely identifies it should define this method.
Overriding predefined model methods¶
There’s another set of model methods that
encapsulate a bunch of database behavior that you’ll want to customize. In
particular you’ll often want to change the way save()
and
delete()
work.
You’re free to override these methods (and any other model method) to alter behavior.
A classic use-case for overriding the built-in methods is if you want something
to happen whenever you save an object. For example (see
save()
for documentation of the parameters it accepts):
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(Blog, self).save(*args, **kwargs) # Call the "real" save() method.
do_something_else()
You can also prevent saving:
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(Blog, self).save(*args, **kwargs) # Call the "real" save() method.
It’s important to remember to call the superclass method – that’s
that super(Blog, self).save(*args, **kwargs)
business – to ensure
that the object still gets saved into the database. If you forget to
call the superclass method, the default behavior won’t happen and the
database won’t get touched.
It’s also important that you pass through the arguments that can be
passed to the model method – that’s what the *args, **kwargs
bit
does. Django will, from time to time, extend the capabilities of
built-in model methods, adding new arguments. If you use *args,
**kwargs
in your method definitions, you are guaranteed that your
code will automatically support those arguments when they are added.
Overridden model methods are not called on bulk operations
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.
Executing custom SQL¶
Another common pattern is writing custom SQL statements in model methods and module-level methods. For more details on using raw SQL, see the documentation on using raw SQL.
モデルの継承¶
Django におけるモデルの継承は Python における普通のクラスの継承とはかなり異なった方法で行われます、しかし最も最初の段階で基本となる考えは共通しています。それはその基底クラスが django.db.models.Model
のサブクラスでなければならないという事です。
下すべき決定事項は親モデルを (保持するデータベースのテーブルと共に) 独自の権限を持ったモデルとするか、それとも親モデルは単に子モデルを通じてのみ参照できる共通情報を持っているだけの存在とするかという事だけです。
Django において可能な継承には 3 つの方式が有ります。
- 往々にして、子モデルそれぞれに対して一々定義し直さないで済ませたい情報を保持するためだけに親クラスを用いようとするでしょう。そのクラスは単体で用いられることはありません、抽象基底クラス こそあなたが必要とする物でしょう。
- もし既存のモデル (完全に別のアプリケーション等から取得した) のサブクラスを作成していてモデルそれぞれにデータベース上のテーブルを定義したい場合、 複数テーブルの継承 を利用するとよいでしょう。
- 最後に、もしあるモデルの Python レベルでの振る舞いを、そのモデルのフィールドをいかなる形でも変更せずに修正したい場合は プロキシモデル を利用できます。
抽象基底クラス¶
抽象基底クラスは大量のモデルに共通の情報を持たせたい場合に有用です。基礎となるクラスを記述してその Meta クラス内に abstract=True
を記述します。そうするとそのモデルはデータベース上にテーブルを構築するために用いられることは無くなります。その変わり、他のモデルの基底クラスとして用いられた場合、そのモデル上のフィールドは子クラスのフィールドに追加されます。抽象基底クラスに定義したのと同じ名前のフィールドが継承した子に存在する場合はエラーとなります (Django が例外を送出します)。
実装例:
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
モデルは name
、age
そして home_group
の 3 つのフィールドを持つことになります。 CommonInfo
モデルは抽象基底クラスであるため、通常の Django モデルとしては利用できません。データベース上にテーブルを生成したりマネージャを持ったりせず、そしてインスタンス化されたり直接値を保存する事もできません。
大抵の状況において、このモデル継承の方式がまさにあなたが必要としていた物となるでしょう。この方式では、データベースの領域では子モデル毎に一つずつだけのテーブルを作る事しかできませんが、共通で持ちたい情報を 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 は抽象基底クラスの Meta クラスに対して一つの変更を施します: Meta 属性を子クラスに導入する前に、 abstract=False
を設定します。これは抽象基底クラスを継承した子クラスは自身を自動的に抽象基底クラスにはしない事を意味します。言うまでもなく、他の抽象基底クラスを継承した抽象基底クラスを作る事はできます。継承する都度 abstract=True
を設定する事を忘れなければ良いだけです。
抽象基底クラスの Meta クラスに持っても意味をなさない属性がいくつか存在します。例えば、属性値 db_table
を持つことは継承した子クラス (の中で自身の Meta を定義していない物) が全て同じデータベース上のテーブルを利用する事を意味しますが、それは期待する動作と明らかに異なるでしょう。
複数テーブルの継承¶
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")
Place
を取得すれば Restaurant
も取得することになり、小文字のモデル名を用いることで Place
オブジェクトから Restaurant
オブジェクトを取得できます:
>>> p = Place.objects.get(id=12)
# If p is a Restaurant object, this will give the child class:
>>> p.restaurant
<Restaurant: ...>
しかしながら、上の例において p
が Restaurant
オブジェクト ではない (継承を用いず Place
オブジェクトが直接作成されたもしくは他のクラスの親であった)場合、 p.restaurant
を参照すると Restaurant.DoesNotExist
例外を創出します。
The automatically-created OneToOneField
on
Restaurant
that links it to Place
looks like this:
place_ptr = models.OneToOneField(
Place, on_delete=models.CASCADE,
parent_link=True,
)
You can override that field by declaring your own
OneToOneField
with parent_link=True
on Restaurant
.
``メタクラス``と複数テーブルの継承¶
複数のテーブルを継承する状況では、子クラスにとって親クラスの 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')
。
親モデルとのリンクに用いるフィールドを定義する¶
先に述べたように、Django は自動的に OneToOneField
による子クラスから抽象クラスでないあらゆる親モデルへの関連付けを自動的に作ります。もしこの親モデルを指す属性値の名前を設定したい場合は、あるフィールドが親クラスに関連を逆引きするための物であることを示すために、独自の OneToOneField
を作り parent_link=True
を設定できます。
プロキシモデル¶
複数テーブルの継承 を利用しているとき、あるモデルのサブクラス毎に新たなデータベースのテーブルが作成されます。これは基底クラスに存在しない追加のデータフィールドをサブクラスが保存する場所が必要なため、通常必要とされる動作です。しかしながら、モデルの 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>
あるモデルに対して並び順の既定値を定義したい場合もプロキシモデルを利用できます。普段は Person
モデルの並び順を特に指定していないが、定期的に last_name
属性に基づいて並び替える場合にプロキシを利用できます。とても簡単に利用できます:
class OrderedPerson(Person):
class Meta:
ordering = ["last_name"]
proxy = True
これで通常の Person
に対する問い合わせでは特に結果は並び替えられず OrderedPerson
に対する問い合わせでは last_name
に基づいて並び替えられます。
プロキシモデルは Meta
の属性値を 通常のモデルと同様に 継承します。
QuerySet
s はリクエストされたモデルを返し続ける¶
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 メソッドを隠ぺいする管理対象外モデルを作成できます。しかしながら、この操作は変更を加えた際に定義を複製して同期する際にとても冗長で変更に弱い物となります。
一方、プロキシモデルはプロキシするモデルと全く同じように振る舞うことを企図しています。それらのモデルは直接フィールドとマネージャーを継承しているため、常に親モデルに同期しています。
原則としては:
- もし既存のモデルやデータベースのテーブルを反映したいが元となるテーブルのカラムの全てを必要とする訳ではない場合は、
Meta.managed=False
を利用してください。このオプションはデータベースのビューやテーブルを Django の管理下に置きたくない場合に通常有用となります。 - もしあるモデルの Python の箇所の振る舞いだけを変更したいが、元となるモデルと同じフィールドを保持したい場合は
Meta.proxy=True
を使用してください。この設定はデータ保存時にプロキシモデルが、元となるモデル側の保管構造の完全な複製となるように諸々を設定します。
多重継承¶
Python におけるサブクラス化と同様に、 Django のモデルは複数の親モデルを継承する事ができます。Python で通常用いられる名前解決の規則が適用されることを念頭に置いてください。特定の名称のオブジェクト (例えば 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_name
と related_query_name
と同じように定義します。
これらの特別な属性はその属性を定義しているフィールドが、もはやその特別な属性を定義しなくなるように、変更もしくは削除されなければオーバーライドできません。
親モデルのフィールドをオーバーライドする事はインスタンス (どのフィールドが初期化されるか Model.__init__
に定義している) の初期化やシリアライズ時の問題につながります。これらは通常の Python のクラス継承で全く同様に扱う事が求められていない機能であるため、 Django のモデル継承と Python のクラス継承のこうした差異は恣意的な設計による物ではありません。
この制限は Field
のインスタンスである属性に対してのみ適用されます。通常の Python の属性は望むままにオーバーライドできます。またその制約は Python が解析する際の属性の名称にのみ影響します:もしデータベースのカラム名を手動で設定したい場合、複数テーブルの継承 (2 つの異なるデータベースのテーブルに保持されているカラム) を表現する際に子と祖先のモデルで同じカラム名を設定できます。
もし祖先モデルのいずれかに定義されたモデルのフィールドをオーバーライドした場合 Django は FieldError
例外を送出します。
パッケージ化したモデルを扱う¶
manage.py startapp
コマンドを実行することで models.py
ファイルを含むアプリケーション構造が作成されます。多数のモデルが存在する場合、それらを別のファイルとして管理するのが良いかもしれません。
それを行うため、 models
パッケージを作成します。 models.py
を削除してモデルを保持するための __init__.py
ファイルを持つ myapp/models/
ディレクトリを作成します。作成した __init__.py
でモデルをインポートする必要が有ります。
例えば、 organic.py
および synthetic.py
を models
ディレクトリ内に持っている場合:
from .organic import Person
from .synthetic import Robot
from .models import *
という記述を用いずに各モデルを明示的にインポートする方法には名前空間を汚染しない、可読性を向上させる、コード解析ツールを有用な状態に保つという利点が有ります。
参考
- モデルの手引き
- Covers all the model related APIs including model fields, related
objects, and
QuerySet
.