このドキュメントでは、Model API の詳細を説明しています。モデル と データベースクエリ ガイドにある説明を前提としていますので、このドキュメントを読む前にこの 2 つを読んでおいた方がよいでしょう。
このリファレンスでは、 データベースクエリガイド で提供された Blogモデルの例 を使用します。
モデルの新しいインスタンスを作成するには、他の Python クラスと同様にインスタンス化してください:
キーワード引数は、モデル内で定義したフィールドの名前です。モデルをインスタンス化しても、データベースには何もしないことに注意してください。データベースとやり取りするには save() を使う必要があります。
注釈
__init__ メソッドをオーバーライドしてモデルをカスタマイズする誘惑に駆られるかもしれません。しかしその場合は、あらゆる変更がモデルインスタンスを保存しないように、呼び出しシグネチャを変更しないように配慮してください。さらに、 __init__ 内でモデルのフィールドを参照すると、状況によっては無限再帰エラーが発生する可能性があります。 __init__ をオーバーライドするのではなく、以下のいずれかのアプローチを試してみてください:
モデルクラスにクラスメソッドを追加する:
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
@classmethod
def create(cls, title):
book = cls(title=title)
# do something with the book
return book
book = Book.create("Pride and Prejudice")
独自のマネジャーにメソッドを追加する (通常推奨される方法です):
class BookManager(models.Manager):
def create_book(self, title):
book = self.create(title=title)
# do something with the book
return book
class Book(models.Model):
title = models.CharField(max_length=100)
objects = BookManager()
book = Book.objects.create_book("Pride and Prejudice")
from_db() メソッドを使うと、データベースから読み込むときのモデルインスタンス作成をカスタマイズできます。
引数 db はモデルを読み込む対象となるデータベースへのエイリアスになります。 field_names は読み込まれるすべてのフィールドの名前を持ち、そして values は field_names 内各フィールドに対応した値を持ちます。 field_names は values と同じ並び順になります。モデルのフィールドが全て存在する場合、 values はその順番が __init__() が期待する順番である事が保障されます。つまり、そのインスタンスは cls(*values) によって生成されます。いずれかのフィールドが遅延評価されている場合、そのフィールドは field_names 内には現れません。その場合、存在しない各フィールドには django.db.models.DEFERRED の値が設定されています。
新しいモデルを作成するだけでなく、from_db() メソッドは新しいインスタンスの _state 属性に adding と db のフラグを設定する必要があります。
以下はデータベースから読み出されたフィールドの初期値をどのように保存しているのかについてを示した例です:
from django.db.models import DEFERRED
@classmethod
def from_db(cls, db, field_names, values):
# Default implementation of from_db() (subject to change and could
# be replaced with super()).
if len(values) != len(cls._meta.concrete_fields):
values = list(values)
values.reverse()
values = [
values.pop() if f.attname in field_names else DEFERRED
for f in cls._meta.concrete_fields
]
instance = cls(*values)
instance._state.adding = False
instance._state.db = db
# customization to store the original field values on the instance
instance._loaded_values = dict(
zip(field_names, (value for value in values if value is not DEFERRED))
)
return instance
def save(self, **kwargs):
# Check how the current values differ from ._loaded_values. For example,
# prevent changing the creator_id of the model. (This example doesn't
# support cases where 'creator_id' is deferred).
if not self._state.adding and (
self.creator_id != self._loaded_values["creator_id"]
):
raise ValueError("Updating the value of creator isn't allowed")
super().save(**kwargs)
上の例ではその機能を明らかにするため from_db() の実装を全て行いました。この実装を行う場合では from_db() メソッドから super() を呼び出してもかまいません。
モデルのインスタンスからあるフィールドを削除した場合、再度アクセスする事でその値をデータベースから再読み込みします:
>>> obj = MyModel.objects.first()
>>> del obj.field
>>> obj.field # Loads the field from the database
非同期バージョン: arefresh_from_db()
データベースからモデルの値を再読み込みする必要がある場合は、 refresh_from_db() メソッドを利用できます。引数なしでこのメソッドを呼び出した場合は以下の処理が行われます:
モデル上の遅延評価されない全てのフィールドはその時点でデータベース上に存在する値に更新されます。
キャッシュされたリレーションは、リロードされたインスタンスから消去されます。
データベースからはフィールドのみが再読み込みされます。それ以外のアノテーションのようなデータベース依存の値は更新されません。同様に @cached_property 属性などはどれもクリアされません。
再読み込みはインスタンスを読み込むデータベースから、もしくはインスタンスがデータベースから読み込まれない場合はデフォルトのデータベースから行われます。 using 引数は再読み込みを行うデータベースを強制的に設定する際に使用できます。
読み込むフィールドのセットを強制的に設定するには fields 引数を使用できます。
たとえば、update() の呼び出しによって期待する更新が行われたかをテストするため、以下のようなテストを書くことができます。
def test_update_result(self):
obj = MyModel.objects.create(val=1)
MyModel.objects.filter(pk=obj.pk).update(val=F("val") + 1)
# At this point obj.val is still 1, but the value in the database
# was updated to 2. The object's updated value needs to be reloaded
# from the database.
obj.refresh_from_db()
self.assertEqual(obj.val, 2)
遅延評価されているフィールドにアクセスした場合、その遅延評価されるフィールドの読み込みはこのメソッドを経由する事に注意してください。そのため遅延評価の読み込みがどのように行われるかを独自に設定できます。以下の例は遅延評価するフィールドが再読み込みされた時どのようにしてインスタンス上のフィールド全てを再読み込みできるかを示しています:
class ExampleModel(models.Model):
def refresh_from_db(self, using=None, fields=None, **kwargs):
# fields contains the name of the deferred field to be
# loaded.
if fields is not None:
fields = set(fields)
deferred_fields = self.get_deferred_fields()
# If any deferred field is going to be loaded
if fields.intersection(deferred_fields):
# then load all of them
fields = fields.union(deferred_fields)
super().refresh_from_db(using, fields, **kwargs)
from_queryset 引数を使用すると、_base_manager から作成されたクエリセットとは異なるクエリセットを使用できます。これにより、モデルの再読み込み方法をより細かく制御できるようになります。例えば、モデルで論理削除を使用している場合、refresh_from_db() を呼び出す際にこれを考慮することができます:
obj.refresh_from_db(from_queryset=MyModel.active_objects.all())
再読み込みされたインスタンスから通常クリアされる関連オブジェクトをキャッシュすることができます。
obj.refresh_from_db(from_queryset=MyModel.objects.select_related("related_field"))
モデルの値を再読み込みする前に、トランザクションの終了まで行をロックすることができます。
obj.refresh_from_db(from_queryset=MyModel.objects.select_for_update())
from_queryset 引数が追加されました。
対象となるモデルにおいて現在評価を遅延している全てのフィールドの属性名を持った集合を返すヘルパーメソッドです。
モデルのバリデーションには 4 つのステップがあります:
モデルフィールドを検証する - Model.clean_fields()
モデル全体を検証する - Model.clean()
フィールドの一意性を検証する - Model.validate_unique()
制約を検証する - Model.validate_constraints()
モデルの full_clean() メソッドを使うと、4 つ全てのステップが実行されます。
ModelForm を使っているとき、is_valid() の呼び出しは、フォーム上に含まれる全てのフィールドに対して、これらの検証ステップを実行します。詳しくは ModelForm ドキュメント を参照してください。検証エラーを自分でコントロールしたい場合、もしくは ModelForm から検証を必要とするフィールドを除外した場合は、モデルの full_clean() メソッドだけを呼び出す必要があります。
このメソッドは、Model.clean_fields()、Model.clean()、 Model.validate_unique() (validate_unique が True の場合)、そして Model.validate_constraints() (validate_constraints が True の場合) をこの順序で呼び出し、4 つ全てのステージでのエラーを含む message_dict 属性を持つ ValidationError を発生させます。
オプションの exclude 引数を指定することで、検証とクリーニングから除外するフィールド名の set を指定できます。ModelForm は、この引数をフォーム上に存在しないフィールドを検証対象から除外するために使います。これは、エラーが発生してもユーザーによって修正できないからです。
モデルの save() メソッドを呼んだときでも full_clean() は自動的に 呼ばれない ことに注意してください。手動で作ったモデルに対して 1 ステップでモデル検証をしたいときには、手動で呼び出す必要があります。次に例を示します。
from django.core.exceptions import ValidationError
try:
article.full_clean()
except ValidationError as e:
# Do something based on the errors contained in e.message_dict.
# Display them to a user, or handle them programmatically.
pass
full_clean() が行う最初のステップは、個々のフィールドをそれぞれクリーニングすることです。
このメソッドはモデル上の全てのフィールドをバリデーションします。オプションの exclude 引数にはバリデーションの対象から除外したいフィールド名の set を渡すことができます。いずれかのフィールドでバリデーションに失敗した場合は ValidationError が送出されます。
full_clean() の第二段階では Model.clean() を呼び出します。このメソッドはモデル独自のバリデーションにオーバーライドされます。
このメソッドは、独自のモデルバリデーションを提供するために使い、必要な場合はモデルの属性を修正できます。たとえば、フィールドに対して自動的に値を提供したり、複数のフィールドにアクセスする必要のあるバリデーションを実施できます。
import datetime
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.translation import gettext_lazy as _
class Article(models.Model):
...
def clean(self):
# Don't allow draft entries to have a pub_date.
if self.status == "draft" and self.pub_date is not None:
raise ValidationError(_("Draft entries may not have a publication date."))
# Set the pub_date for published items if it hasn't been set already.
if self.status == "published" and self.pub_date is None:
self.pub_date = datetime.date.today()
ただし、Model.full_clean() と同様に、モデルの clean() メソッドは、save() メソッドが呼ばれたときには実行されないことに注意してください。
上の例では、Model.clean() により発生した ValidationError 例外は文字列によりインスタンス化されていたので、特別なエラーディクショナリのキー NON_FIELD_ERRORS に保存されます。このキーは、特定のフィールドではなくモデル全体に関連付けられたエラーに使用します:
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
try:
article.full_clean()
except ValidationError as e:
non_field_errors = e.message_dict[NON_FIELD_ERRORS]
例外を特定のフィールドにアサインするには、ディクショナリで ValidationError をインスタンス化し、キーにフィールド名を指定してください。上記の例を変更して、pub_date フィールドにエラーをアサインします:
class Article(models.Model):
...
def clean(self):
# Don't allow draft entries to have a pub_date.
if self.status == "draft" and self.pub_date is not None:
raise ValidationError(
{"pub_date": _("Draft entries may not have a publication date.")}
)
...
Model.clean() 実施中に複数フィールドでエラーを発見した場合、ディクショナリを渡してエラーにフィールド名をマップすることもできます:
raise ValidationError(
{
"title": ValidationError(_("Missing title."), code="required"),
"pub_date": ValidationError(_("Invalid date."), code="invalid"),
}
)
そして、full_clean() でモデル上のユニーク制約をチェックします。
ModelForm 内に表示されないフィールドに対してフィールド特有のバリデーションエラーを発生させる方法
(Meta.fields や Meta.exclude で制限されて) モデルフォームに表示されないフィールドに対して Model.clean() 内でバリデーションエラーを発生させることはできません。やろうとしても、ValueError が発生します。これは、バリデーションエラーが除外されたフィールドと関連付けることができないからです。
このジレンマに対応するには、Model.clean_fields() をオーバーライドすることです。これはバリデーションから除外されたフィールドのリストを受け取ります。次に例を示します。
class Article(models.Model):
...
def clean_fields(self, exclude=None):
super().clean_fields(exclude=exclude)
if self.status == "draft" and self.pub_date is not None:
if exclude and "status" in exclude:
raise ValidationError(
_("Draft entries may not have a publication date.")
)
else:
raise ValidationError(
{
"status": _(
"Set status to draft if there is not a publication date."
),
}
)
このメソッドは clean_fields() と似ていますが、個別のフィールドの値ではなく Field.unique, Field.unique_for_date, Field.unique_for_month, Field.unique_for_year, Meta.unique_together によって定義されたユニーク制約を検証します。オプションの exclude 引数により、バリデーションから除外するフィールド名の set を指定できます。いずれかのフィールドがバリデーションに失敗した場合、ValidationError を発生させます。
Meta.constraints で定義された UniqueConstraint は Model.validate_constraints() によって検証されます。
validate_unique() で exclude 引数を指定した場合、そのうちの 1 つでも含む unique_together 制限はチェックされません。
最後に、full_clean() でモデル上の他の制約をチェックします。
このメソッドは Meta.constraints で定義された全ての制約を検証します。オプションの exclude 引数で、検証から除外するフィールド名の set を指定できます。制約の検証に失敗した場合、 ValidationError を発生させます。
データベースにオブジェクトを保存し直すには、save() を呼び出します:
非同期バージョン: asave()
force_insert と force_update 引数の詳細については INSERT や UPDATE を強制する を参照してください。引数 update_fields の詳細については どのフィールドを保存するか指定する セクションを参照してください。
保存の動作をカスタマイズしたい場合は、save() メソッドをオーバーライドできます。詳しくは 定義済みのモデルメソッドをオーバーライドする を参照してください。
モデル保存のプロセスには、いくつかの細かな注意点もあります; 以下の各セクションを参照してください。
Deprecated since version 5.1: 位置引数のサポートは非推奨になりました。
モデルに AutoField (自動インクリメントのプライマリキー) がある場合、最初に save() を呼び出すと、自動インクリメントの値が計算され、オブジェクトの属性として保存されます:
>>> b2 = Blog(name="Cheddar Talk", tagline="Thoughts on cheese.")
>>> b2.id # Returns None, because b2 doesn't have an ID yet.
>>> b2.save()
>>> b2.id # Returns the ID of your new object.
save() を呼び出す前に、ID の値がどうなるかを知る方法はありません。 なぜなら、その値は Django ではなくデータベースが計算するからです。
利便性のために、各モデルには id という AutoField がデフォルトで用意されていますが、モデル内のフィールドに primary_key=True を明示的に指定しない限り、 id という名前のフィールドは用意されません。詳しくは AutoField のドキュメントを参照してください。
pk プロパティ¶プライマリキーフィールドを自分で定義するか、 Django が用意してくれるかに関わらず、各モデルには pk というプロパティがあります。このプロパティはモデル上では普通の属性のように振る舞いますが、実際にはモデルのプライマリキーフィールドの属性のエイリアスです。他の属性と同じように、この値を読み込んだり指定したりすることができ、モデルの正しいフィールドを更新します。
モデルが AutoField を持っていて、保存時に新しいオブジェクトの ID を明示的に定義したい場合は、ID の自動割り当てに頼るのではなく、保存前に明示的に定義してください:
>>> b3 = Blog(id=3, name="Cheddar Talk", tagline="Thoughts on cheese.")
>>> b3.id # Returns 3.
>>> b3.save()
>>> b3.id # Returns 3.
自動プライマリキー値を手動で割り当てる場合は、既に存在するプライマリキー 値を使わないようにしてください!すでにデータベースに存在する明示的なプライマリキー値を使って新しいオブジェクトを作成すると、 Django は新しいレコードを作成するのではなく、既存のレコードを変更するものとみなし ます。
上記の 'Cheddar Talk' ブログの例を考えると、この例はデータベースの以前のレコードを上書きします:
b4 = Blog(id=3, name="Not Cheddar", tagline="Anything but cheese.")
b4.save() # Overrides the previous blog with ID=3!
このようなことが起こる理由については、後述の How Django knows to UPDATE vs. INSERT を参照してください。
自動プライマリキーの値を明示的に指定することは、プライマリキーの衝突が起きないと確信が持てる場合に、オブジェクトを一括保存するときに便利です。
PostgreSQLを使用している場合、プライマリキーに関連付けられたシーケンスを更新する必要があるかもしれません。 自動インクリメントのプライマリキーの値を手動で指定する を参照してください。
オブジェクトを保存するとき、Django は以下のステップを実行します:
pre-save シグナルを発信します。 pre_save シグナルが送られ、そのシグナルを待ち受ける関数が何かできるようになります。
データの前処理。 各フィールドの pre_save() メソッドが呼び出され、必要な自動データ修正を行います。たとえば、日付/時刻フィールドは pre_save() をオーバーライドして auto_now_add と auto_now を実装しています。
データベース用のデータを準備します。 各フィールドの get_db_prep_save() メソッドは、データベースに書き込めるデータ型で現在の値を提供するように要求されます。
ほとんどのフィールドではデータの準備は不要です。整数や文字列のような単純なデータ型は Python オブジェクトとして 'すぐに書けます' 。しかし、より複雑なデータ型はしばしば何らかの変更を必要とします。
たとえば、 DateField フィールドは Python の datetime オブジェクトを使ってデータを格納します。データベースは datetime オブジェクトを保存しないので、フィールドの値を ISO 準拠の日付文字列に変換してデータベースに挿入する必要があります。
データベースにデータを挿入します。 前処理され準備されたデータは、データベースに挿入するためのSQL文に構成されます。
post-save シグナルを発信します。 post_save シグナルが送られ、 そのシグナルを待ち受ける関数が何かできるようになります。
Django データベースオブジェクトが、オブジェクトの作成と変更に同じ save() メソッドを使うことにお気づきかもしれません。Django は INSERT や UPDATE といった SQL ステートメントを抽象化しています。具体的には、 save() を呼び出し、オブジェクトのプライマリキー属性に default や db_default が 定義されていない場合 、Django はこのアルゴリズムに従います:
If the object's primary key attribute is set to anything except None,
Django executes an UPDATE.
オブジェクトのプライマリキー属性がセット されていない、もしくは UPDATE が何もアップデートしなかった場合 (プライマリキーがデータベースに存在しない値に指定されている場合など) 、Django は INSERT を実行します。
オブジェクトのプライマリキー属性に default や db_default が定義されている場合は既存のモデルインスタンスで、プライマリキーにデータベースに存在する値が指定されていれば、Django は UPDATE を実行します。そうでない場合、 Django は INSERT を実行します。
ここで重要なのは、そのプライマリキーが使われていないことが保証できない場合、新しいオブジェクトを保存するときに明示的にプライマリキーの値を指定しないように気をつけることです。このニュアンスについては、上述の 自動プライマリキーの値を明示的に指定する と下記の INSERT や UPDATE を強制する を参照してください。
Django 1.5 以前のバージョンでは、Django はプライマリキー属性が指定されると SELECT を行いました。 SELECT で行が見つかれば UPDATE を行い、見つからなければ INSERT を行いました。古いアルゴリズムでは、 UPDATE の場合にクエリが 1 つ増えます。まれに、データベースにオブジェクトのプライマリキー値の行があっても、その行が更新されたことを報告しない場合があります。たとえば、PostgreSQLの ON UPDATE トリガは NULL を返します。このような場合、 select_on_save オプションを True に設定することで、古いアルゴリズムに戻すことができます。
Field.db_default パラメータが追加されました。
まれに、save() メソッドにSQLの INSERT を強制的に実行させ、UPDATE にフォールバックさせないようにする必要がある場合があります。またはその逆で、可能であれば更新を行い、新しい行を挿入しないようにする必要がある場合もあります。これらの場合には、save() メソッドに force_insert=True または force_update=True パラメータを渡すことができます。両方のパラメータを渡すとエラーになります。挿入と更新を 同時に 行うことはできません!
マルチテーブル継承 を使用する場合、force_insert に親クラスのタプルを渡すことで、各ベースに対して INSERT ステートメントを強制的に挿入できます。たとえば次のようになります:
Restaurant(pk=1, name="Bob's Cafe").save(force_insert=(Place,))
Restaurant(pk=1, name="Bob's Cafe", rating=4).save(force_insert=(Place, Rating))
force_insert=(models.Model,) を渡すことで、すべての親モデルに対して INSERT ステートメントを強制的に挿入できます。デフォルトでは、 force_insert=True は現在のモデルに対してのみ新しい行の挿入を強制します。
これらのパラメータを必要とするのは、まれであるべきです。Django は、ほとんどの場合で正しく処理を行い、オーバーライドしようとすると追跡が難しいエラーの原因となります。この機能は応用的な場合のみに使用してください。
update_fields を使うと force_update と同じように更新を強制します。
force_insert に親クラスのタプルを渡せるようになりました。
フィールドに対して、現在の値をインクリメントしたりデクリメントしたりするような単純な計算が必要になることがあります。これを実現する1つの方法は、Pythonで次のように計算を行うことです:
>>> product = Product.objects.get(name="Venezuelan Beaver Cheese")
>>> product.number_sold += 1
>>> product.save()
データベースから取得した古い number_sold の値は 10 でした。そして、11 という値がデータベースに書き直されます。
この処理は、 競合状態 を回避し、堅牢性を向上させます。また、新しい値を明示的に代入するのではなく、元のフィールド値からの相対的な更新を表現することで、若干高速になります。 Djangoには、このような相対的な更新を行うための F 式 があります。 F 式 を使うと、上の例は以下のように表されます:
>>> from django.db.models import F
>>> product = Product.objects.get(name="Venezuelan Beaver Cheese")
>>> product.number_sold = F("number_sold") + 1
>>> product.save()
save() にキーワード引数 update_fields 内でフィールドリストの名前が渡された場合、このリスト内で指定されたフィールドだけが更新されます。これは、オブジェクトの 1 つないし少数のフィールドだけを更新したい場合に望ましいでしょう。データベースで全てのモデルフィールドを更新しないようにすると、実行速度が少し向上します。例えば:
product.name = "Name changed again"
product.save(update_fields=["name"])
update_fields 引数は文字列を含む任意のイテラブルです。空の update_fields イテラブルは保存をスキップします。 None という値は全てのフィールドを更新します。
update_fields を指定すると更新を強制します。
遅延モデルローディング (only() や defer()) を通してフェッチされたモデルを保存するとき、DB からロードされたフィールドだけが更新されます。実際には、このケースでは自動的な update_fields が存在します。遅延フィールドの値を追加もしくは変更した場合、フィールドは更新されたフィールドに追加されます。
Field.pre_save() と update_fields
update_fields が渡された場合、 update_fields の pre_save() メソッドのみが呼び出されます。たとえば、これは auto_now=True の日付/時刻フィールドが update_fields に含まれない限り更新されないことを意味します。
非同期バージョン: adelete()
オブジェクトに対して SQL の DELETE を発行します。Python のインスタンスはまだ存在し、プライマリキーが None に設定されている以外は、そのフィールドにデータが残っています。このメソッドは削除されたオブジェクトの数と、オブジェクトの種類ごとの削除数を辞書として返します。
より詳しく (まとめてオブジェクトを削除する方法を含む) については、オブジェクトを削除する を参照してください。
独自の削除動作がほしいときは、delete() メソッドをオーバーライドできます。詳しくは 定義済みのモデルメソッドをオーバーライドする を参照してください。
マルチテーブル継承 では、子モデルのデータだけを削除したい場合があります。keep_parents=True を指定すると、親モデルのデータを保持します。
モデルを pickle 化した時、現在の状態はpickle化された状態です。pickle化を解除すると、現在データベースにあるデータではなく、pickle化した時点のモデルインスタンスが格納されます。
いくつかのオブジェクトメソッドには特別な目的があります。
__str__()¶オブジェクトに対して str() を呼び出すと、 __str__() メソッドが呼び出されます。Django は多くの場所で str(obj) を使います。特に、 Django の管理サイトでオブジェクトを表示するときや、テンプレートでオブジェクトを表示するときに挿入される値として使われます。したがって、 __str__() メソッドからは、常に人間が読めるようなモデルの表現を返さなければなりません。
例:
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
def __str__(self):
return f"{self.first_name} {self.last_name}"
__eq__()¶等式メソッドは次のように定義されています: 同じプライマリキー値と具体的なクラスを持つインスタンスは等しいと見なされますが、プライマリキー値が None のインスタンスはそれ自身以外のものと等しくありません。プロキシモデルの場合、具体的なクラスはモデルの最初の非プロキシ親として定義されます。他のモデルについては、単純にモデルのクラス自体です。
例:
from django.db import models
class MyModel(models.Model):
id = models.AutoField(primary_key=True)
class MyProxyModel(MyModel):
class Meta:
proxy = True
class MultitableInherited(MyModel):
pass
# Primary keys compared
MyModel(id=1) == MyModel(id=1)
MyModel(id=1) != MyModel(id=2)
# Primary keys are None
MyModel(id=None) != MyModel(id=None)
# Same instance
instance = MyModel(id=None)
instance == instance
# Proxy model
MyModel(id=1) == MyProxyModel(id=1)
# Multi-table inheritance
MyModel(id=1) != MultitableInherited(id=1)
__hash__()¶__hash__() メソッドはインスタンスのプライマリキー値に基づいています。実質的には hash(obj.pk) です。インスタンスにプライマリキー値がない場合は TypeError が発生します(そうでないと、インスタンスが保存される前後で __hash__() メソッドが異なる値を返すことになりますが、Pythonではインスタンスの __hash__() 値を変更することは禁止されています)。
get_absolute_url()¶オブジェクトに対する正式な URL を計算する方法は、get_absolute_url() で定義します。呼び出し元に対して、このメソッドは文字列を返します。この文字列は HTTP を通じてオブジェクトを参照するために使えるものです。
例:
def get_absolute_url(self):
return "/people/%i/" % self.id
このコードは正しくかつシンプルですが、この種のメソッドを記述するのに最も適した方法です。reverse() 関数が一般的にベストアプローチとなります。
例:
def get_absolute_url(self):
from django.urls import reverse
return reverse("people-detail", kwargs={"pk": self.pk})
Django が get_absolute_url() を使う場所の一つが、admin アプリです。オブジェクトにこのメソッドが定義されている場合、オブジェクト編集のページは "View on site" リンクを持つようになり、get_absolute_url() で定義された通りオブジェクトの公開用ビューに直接飛べるようになります。
同様に、Django の他にもいくつか、get_absolute_url() が定義されている場合に使用するものがあります (配信フィードフレームワーク など)。 各モデルインスタンスがユニークな URL を持つことが適切な場合、get_absolute_url() を定義すべきです。
警告
リダイレクトポイズニングの可能性を減らすため、検証されていないユーザーの入力を利用した URL の生成は避けてください。
def get_absolute_url(self):
return "/%s/" % self.name
self.name が '/example.com' の場合、上記は '//example.com/' を返します。これは有効な schema relative URL ですが、期待されていた '/%2Fexample.com/' ではありません。
テンプレート内で、ハードコーディングしたオブジェクトの URL ではなく get_absolute_url() を使うのは良い実装方法です。以下のテンプレートコードは悪い例です:
<!-- BAD template code. Avoid! -->
<a href="/people/{{ object.id }}/">{{ object.name }}</a>
以下のテンプレートコードは改善例です:
<a href="{{ object.get_absolute_url }}">{{ object.name }}</a>
このロジックのポイントは、オブジェクトのURL構造を変更する場合、スペルミス修正のような些細な変更であっても、URLが生成される場所すべてを修正する必要がないようにすることです。 get_absolute_url() メソッドでURLを一度定義しておけば、コード全体でそのメソッドを呼び出すだけで済みます。
注釈
get_absolute_url() メソッドから返される文字列は、必ず ASCII 文字のみを含み (URI 仕様 RFC 3986 Section 2 で必須)、必要に応じてURLエンコードする必要があります。
get_absolute_url() メソッドを呼び出すコードやテンプレートは、結果をそのまま使用でき、 さらに処理する必要はありません 。ASCII 文字以外の文字を含む文字列を使用している場合は、django.utils.encoding.iri_to_uri() 関数を使用して変換すると便利です。
モデルオブジェクトは save(), delete() に加えて、以下のメソッドを持つことがあります:
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=2, choices=SHIRT_SIZES)
>>> p = Person(name="Fred Flintstone", shirt_size="L")
>>> p.save()
>>> p.shirt_size
'L'
>>> p.get_shirt_size_display()
'Large'
null=True を持たない DateField と DateTimeField に対して、オブジェクトは get_next_by_FOO() と get_previous_by_FOO() メソッドを持ちます。このメソッドは日付フィールドに関する次のオブジェクトと前のオブジェクトを返し、適切な場合には DoesNotExist 例外を発生させます。
これらのメソッドはどちらもモデルのデフォルトマネージャを使用してクエリを実行します。カスタムマネージャによるフィルタリングをエミュレートする必要がある場合、あるいは単発のカスタムフィルタリングを実行したい場合、どちらのメソッドもオプションのキーワード引数を受け付けます。キーワード引数は フィールドルックアップ で説明されている形式でなければなりません。
同じ日付の値の場合、これらのメソッドはプライマリ・キーを同値の判定に使用することに注意してください。これにより、レコードがスキップされたり重複したりしないことが保証されます。つまり、これらのメソッドを未保存のオブジェクトで使用することはできないということです。
追加のインスタンスメソッドのオーバーライド
ほとんどの場合、 get_FOO_display(), get_next_by_FOO(), get_previous_by_FOO() をオーバーライドまたは継承すると、期待通りに動作するはずです。しかし、これらはメタクラスによって追加されるので、すべての継承構造を考慮することは現実的ではありません。より複雑なケースでは、 Field.contribute_to_class() をオーバーライドして、必要なメソッドを設定する必要があります。
_state¶_state 属性はモデルインスタンスのライフサイクルを追跡する ModelState オブジェクトを参照します。
ModelState オブジェクトには 2 つの属性があります: モデルがまだデータベースに保存されていない場合に True となるフラグ adding と、インスタンスが読み込まれた、または保存されたデータベースのエイリアスを指す文字列 db です。
新しくインスタンス化されたインスタンスには adding=True と db=None がセットされます。 QuerySet から取得したインスタンスには adding=False と db がセットされ、関連するデータベースのエイリアスが設定されます。
4月 02, 2025