モデルインスタンスリファレンス

このドキュメントでは、Model API の詳細を説明しています。モデルデータベースクエリ ガイドにある説明を前提としていますので、このドキュメントを読む前にこの 2 つを読んでおいた方がよいでしょう。

このリファレンスでは、 データベースクエリガイド で提供された Blogモデルの例 を使用します。

オブジェクトを作成する

モデルの新しいインスタンスを作成するには、他の Python クラスと同様にインスタンス化してください:

class Model(**kwargs)[ソース]

キーワード引数は、モデル内で定義したフィールドの名前です。モデルをインスタンス化しても、データベースには何もしないことに注意してください。データベースとやり取りするには save() を使う必要があります。

注釈

__init__ メソッドをオーバーライドしてモデルをカスタマイズする誘惑に駆られるかもしれません。しかしその場合は、あらゆる変更がモデルインスタンスを保存しないように、呼び出しシグネチャを変更しないように配慮してください。さらに、 __init__ 内でモデルのフィールドを参照すると、状況によっては無限再帰エラーが発生する可能性があります。 __init__ をオーバーライドするのではなく、以下のいずれかのアプローチを試してみてください:

  1. モデルクラスにクラスメソッドを追加する:

    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")
    
  2. 独自のマネジャーにメソッドを追加する (通常推奨される方法です):

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

モデルの読み込みをカスタマイズする

classmethod Model.from_db(db, field_names, values)[ソース]

from_db() メソッドを使うと、データベースから読み込むときのモデルインスタンス作成をカスタマイズできます。

引数 db はモデルを読み込む対象となるデータベースへのエイリアスになります。 field_names は読み込まれるすべてのフィールドの名前を持ち、そして valuesfield_names 内各フィールドに対応した値を持ちます。 field_namesvalues と同じ並び順になります。モデルのフィールドが全て存在する場合、 values はその順番が __init__() が期待する順番である事が保障されます。つまり、そのインスタンスは cls(*values) によって生成されます。いずれかのフィールドが遅延評価されている場合、そのフィールドは field_names 内には現れません。その場合、存在しない各フィールドには django.db.models.DEFERRED の値が設定されています。

新しいモデルを作成するだけでなく、from_db() メソッドは新しいインスタンスの _state 属性に addingdb のフラグを設定する必要があります。

以下はデータベースから読み出されたフィールドの初期値をどのように保存しているのかについてを示した例です:

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
Model.refresh_from_db(using=None, fields=None, from_queryset=None)[ソース]
Model.arefresh_from_db(using=None, fields=None, from_queryset=None)

非同期バージョン: arefresh_from_db()

データベースからモデルの値を再読み込みする必要がある場合は、 refresh_from_db() メソッドを利用できます。引数なしでこのメソッドを呼び出した場合は以下の処理が行われます:

  1. モデル上の遅延評価されない全てのフィールドはその時点でデータベース上に存在する値に更新されます。

  2. キャッシュされたリレーションは、リロードされたインスタンスから消去されます。

データベースからはフィールドのみが再読み込みされます。それ以外のアノテーションのようなデータベース依存の値は更新されません。同様に @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)

The from_queryset argument allows using a different queryset than the one created from _base_manager. It gives you more control over how the model is reloaded. For example, when your model uses soft deletion you can make refresh_from_db() to take this into account:

obj.refresh_from_db(from_queryset=MyModel.active_objects.all())

You can cache related objects that otherwise would be cleared from the reloaded instance:

obj.refresh_from_db(from_queryset=MyModel.objects.select_related("related_field"))

You can lock the row until the end of transaction before reloading a model's values:

obj.refresh_from_db(from_queryset=MyModel.objects.select_for_update())
Changed in Django 5.1:

The from_queryset argument was added.

Model.get_deferred_fields()[ソース]

対象となるモデルにおいて現在評価を遅延している全てのフィールドの属性名を持った集合を返すヘルパーメソッドです。

オブジェクトを検証 (バリデーション) する

モデルのバリデーションには 4 つのステップがあります:

  1. モデルフィールドを検証する - Model.clean_fields()

  2. モデル全体を検証する - Model.clean()

  3. フィールドの一意性を検証する - Model.validate_unique()

  4. 制約を検証する - Model.validate_constraints()

モデルの full_clean() メソッドを使うと、4 つ全てのステップが実行されます。

ModelForm を使っているとき、is_valid() の呼び出しは、フォーム上に含まれる全てのフィールドに対して、これらの検証ステップを実行します。詳しくは ModelForm ドキュメント を参照してください。検証エラーを自分でコントロールしたい場合、もしくは ModelForm から検証を必要とするフィールドを除外した場合は、モデルの full_clean() メソッドだけを呼び出す必要があります。

Model.full_clean(exclude=None, validate_unique=True, validate_constraints=True)[ソース]

このメソッドは、Model.clean_fields()Model.clean()Model.validate_unique() (validate_uniqueTrue の場合)、そして Model.validate_constraints() (validate_constraintsTrue の場合) をこの順序で呼び出し、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() が行う最初のステップは、個々のフィールドをそれぞれクリーニングすることです。

Model.clean_fields(exclude=None)[ソース]

このメソッドはモデル上の全てのフィールドをバリデーションします。オプションの exclude 引数にはバリデーションの対象から除外したいフィールド名の set を渡すことができます。いずれかのフィールドでバリデーションに失敗した場合は ValidationError が送出されます。

full_clean() の第二段階では Model.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.fieldsMeta.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."
                        ),
                    }
                )
Model.validate_unique(exclude=None)[ソース]

このメソッドは clean_fields() と似ていますが、個別のフィールドの値ではなく Field.unique, Field.unique_for_date, Field.unique_for_month, Field.unique_for_year, Meta.unique_together によって定義されたユニーク制約を検証します。オプションの exclude 引数により、バリデーションから除外するフィールド名の set を指定できます。いずれかのフィールドがバリデーションに失敗した場合、ValidationError を発生させます。

Meta.constraints で定義された UniqueConstraintModel.validate_constraints() によって検証されます。

validate_unique()exclude 引数を指定した場合、そのうちの 1 つでも含む unique_together 制限はチェックされません。

最後に、full_clean() でモデル上の他の制約をチェックします。

Model.validate_constraints(exclude=None)[ソース]

このメソッドは Meta.constraints で定義された全ての制約を検証します。オプションの exclude 引数で、検証から除外するフィールド名の set を指定できます。制約の検証に失敗した場合、 ValidationError を発生させます。

オブジェクトを保存する

データベースにオブジェクトを保存し直すには、save() を呼び出します:

Model.save(*, force_insert=False, force_update=False, using=DEFAULT_DB_ALIAS, update_fields=None)[ソース]
Model.asave(*, force_insert=False, force_update=False, using=DEFAULT_DB_ALIAS, update_fields=None)

非同期バージョン: asave()

force_insertforce_update 引数の詳細については INSERT や UPDATE を強制する を参照してください。引数 update_fields の詳細については どのフィールドを保存するか指定する セクションを参照してください。

保存の動作をカスタマイズしたい場合は、save() メソッドをオーバーライドできます。詳しくは 定義済みのモデルメソッドをオーバーライドする を参照してください。

モデル保存のプロセスには、いくつかの細かな注意点もあります; 以下の各セクションを参照してください。

バージョン 5.1 で非推奨: Support for positional arguments is deprecated.

自動インクリメントのプライマリキー

モデルに 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 プロパティ

Model.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を使用している場合、主キーに関連付けられたシーケンスを更新する必要があるかもしれません。 自動インクリメントの主キーの値を手動で指定する を参照してください。

save すると何が起きるか?

オブジェクトを保存するとき、Django は以下のステップを実行します:

  1. pre-save シグナルを発信します。 pre_save シグナルが送られ、そのシグナルを待ち受ける関数が何かできるようになります。

  2. データの前処理。 各フィールドの pre_save() メソッドが呼び出され、必要な自動データ修正を行います。たとえば、日付/時刻フィールドは pre_save() をオーバーライドして auto_now_addauto_now を実装しています。

  3. データベース用のデータを準備します。 各フィールドの get_db_prep_save() メソッドは、データベースに書き込めるデータ型で現在の値を提供するように要求されます。

    ほとんどのフィールドではデータの準備は不要です。整数や文字列のような単純なデータ型は Python オブジェクトとして 'すぐに書けます' 。しかし、より複雑なデータ型はしばしば何らかの変更を必要とします。

    たとえば、 DateField フィールドは Python の datetime オブジェクトを使ってデータを格納します。データベースは datetime オブジェクトを保存しないので、フィールドの値を ISO 準拠の日付文字列に変換してデータベースに挿入する必要があります。

  4. データベースにデータを挿入します。 前処理され準備されたデータは、データベースに挿入するためのSQL文に構成されます。

  5. post-save シグナルを発信します。 post_save シグナルが送られ、 そのシグナルを待ち受ける関数が何かできるようになります。

Django が UPDATE と INSERT を見分ける方法

Django データベースオブジェクトが、オブジェクトの作成と変更に同じ save() メソッドを使うことにお気づきかもしれません。Django は INSERTUPDATE といった SQL ステートメントを抽象化しています。具体的には、 save() を呼び出し、オブジェクトの主キー属性に defaultdb_default定義されていない場合 、Django はこのアルゴリズムに従います:

  • オブジェクトのプライマリキー属性が True と評価される値にセットされている場合 (たとえば None や空の文字列以外の場合)。Django は UPDATE を実行します。

  • オブジェクトのプライマリキー属性がセット されていない、もしくは UPDATE が何もアップデートしなかった場合 (主キーがデータベースに存在しない値に指定されている場合など) 、Django は INSERT を実行します。

オブジェクトの主キー属性に defaultdb_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 に設定することで、古いアルゴリズムに戻すことができます。

Changed in Django 5.0:

Field.db_default パラメータが追加されました。

INSERT や UPDATE を強制する

まれに、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 と同じように更新を強制します。

Changed in Django 5.0:

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

詳しくは、F とこれに対する 更新クエリ内で使う を参照してください。

どのフィールドを保存するか指定する

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_fieldspre_save() メソッドのみが呼び出されます。たとえば、これは auto_now=True の日付/時刻フィールドが update_fields に含まれない限り更新されないことを意味します。

オブジェクトを削除する

Model.delete(using=DEFAULT_DB_ALIAS, keep_parents=False)[ソース]
Model.adelete(using=DEFAULT_DB_ALIAS, keep_parents=False)

非同期バージョン: adelete()

オブジェクトに対して SQL の DELETE を発行します。Python のインスタンスはまだ存在し、プライマリキーが None に設定されている以外は、そのフィールドにデータが残っています。このメソッドは削除されたオブジェクトの数と、オブジェクトの種類ごとの削除数を辞書として返します。

より詳しく (まとめてオブジェクトを削除する方法を含む) については、オブジェクトを削除する を参照してください。

独自の削除動作がほしいときは、delete() メソッドをオーバーライドできます。詳しくは 定義済みのモデルメソッドをオーバーライドする を参照してください。

複数テーブルの継承 では、子モデルのデータだけを削除したい場合があります。keep_parents=True を指定すると、親モデルのデータを保持します。

オブジェクトの Pickle 化

モデルを pickle 化した時、現在の状態はpickle化された状態です。pickle化を解除すると、現在データベースにあるデータではなく、pickle化した時点のモデルインスタンスが格納されます。

バージョン間でpickle化されたデータを共有することはできません

モデルの pickle は、生成に使われた Django のバージョンでのみ有効です。Django バージョン N を使って pickle を生成した場合、その pickle が Django バージョン N+1 で読める保証はありません。pickle を長期的なアーカイブ戦略の一部として使うべきではありません。

pickle の互換性エラーは、静的に衝突したオブジェクトのように判定が難しいことがあるので、モデルをpickle化したデータを別のバージョンで復元しようとすると RuntimeWarning が送出されます。

その他のモデルインスタンスメソッド

いくつかのオブジェクトメソッドには特別な目的があります。

__str__()

Model.__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__()

Model.__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__()

Model.__hash__()[ソース]

__hash__() メソッドはインスタンスの主キー値に基づいています。実質的には hash(obj.pk) です。インスタンスに主キー値がない場合は TypeError が発生します(そうでないと、インスタンスが保存される前後で __hash__() メソッドが異なる値を返すことになりますが、Pythonではインスタンスの __hash__() 値を変更することは禁止されています)。

get_absolute_url()

Model.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() に加えて、以下のメソッドを持つことがあります:

Model.get_FOO_display()

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'
Model.get_next_by_FOO(**kwargs)
Model.get_previous_by_FOO(**kwargs)

null=True を持たない DateFieldDateTimeField に対して、オブジェクトは 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

Model._state

_state 属性はモデルインスタンスのライフサイクルを追跡する ModelState オブジェクトを参照します。

ModelState オブジェクトには 2 つの属性があります: モデルがまだデータベースに保存されていない場合に True となるフラグ adding と、インスタンスが読み込まれた、または保存されたデータベースのエイリアスを指す文字列 db です。

新しくインスタンス化されたインスタンスには adding=Truedb=None がセットされます。 QuerySet から取得したインスタンスには adding=Falsedb がセットされ、関連するデータベースのエイリアスが設定されます。

Back to Top