モデルインスタンスリファレンス—Djangoドキュメント

提供:Dev Guides
< DjangoDjango/docs/3.2.x/ref/models/instances
移動先:案内検索

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

このドキュメントでは、Model APIの詳細について説明します。 モデルおよびデータベースクエリガイドに記載されている資料に基づいているため、このドキュメントを読む前に、これらのドキュメントを読んで理解することをお勧めします。

このリファレンス全体を通して、データベースクエリガイドに示されているサンプルウェブログモデルを使用します。

オブジェクトの作成

モデルの新しいインスタンスを作成するには、他のPythonクラスと同じようにインスタンス化します。

class Model(**kwargs)

キーワード引数は、モデルで定義したフィールドの名前です。 モデルのインスタンス化はデータベースに影響を与えないことに注意してください。 そのためには、 save()する必要があります。

ノート

__init__メソッドをオーバーライドして、モデルをカスタマイズしたくなるかもしれません。 ただし、そうする場合は、呼び出し側の署名を変更しないように注意してください。変更すると、モデルインスタンスが保存されなくなる可能性があります。 __init__をオーバーライドするのではなく、次のいずれかのアプローチを使用してみてください。

  1. モデルクラスにclassmethodを追加します。

    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には、ロードされたすべてのフィールドの名前が含まれ、valuesには、の各フィールドのロードされた値が含まれます。 field_namesfield_namesvaluesと同じ順序です。 モデルのすべてのフィールドが存在する場合、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, values))
    return instance

def save(self, *args, **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(*args, **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)

データベースからモデルの値を再ロードする必要がある場合は、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)
Model.get_deferred_fields()

このモデルで現在延期されているすべてのフィールドの属性名を含むセットを返すヘルパーメソッド。


オブジェクトの検証

モデルの検証には、次の3つのステップが含まれます。

  1. モデルフィールドを検証します- Model.clean_fields()
  2. モデル全体を検証します- Model.clean()
  3. フィールドの一意性を検証します- Model.validate_unique()

モデルの full_clean()メソッドを呼び出すと、3つのステップすべてが実行されます。

ModelForm を使用する場合、 is_valid()を呼び出すと、フォームに含まれるすべてのフィールドに対してこれらの検証手順が実行されます。 詳細については、 ModelFormのドキュメントを参照してください。 検証エラーを自分で処理する予定がある場合、または検証が必要なフィールドを ModelForm から除外した場合にのみ、モデルの full_clean()メソッドを呼び出す必要があります。

Model.full_clean(exclude=None, validate_unique=True)

このメソッドは、 Model.clean_fields()Model.clean()、および Model.validate_unique()を呼び出します(validate_uniqueTrue)、この順序で、3つのステージすべてからのエラーを含むmessage_dict属性を持つ ValidationError を発生させます。

オプションのexclude引数を使用して、検証とクリーニングから除外できるフィールド名のリストを提供できます。 ModelForm は、この引数を使用して、フォームに存在しないフィールドを検証から除外します。これは、発生したエラーをユーザーが修正できなかったためです。

モデルの save()メソッドを呼び出すと、full_clean()は自動的に呼び出されないことに注意してください。 手動で作成した独自のモデルに対してワンステップモデル検証を実行する場合は、手動で呼び出す必要があります。 例えば:

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引数を使用すると、検証から除外するフィールド名のリストを提供できます。 いずれかのフィールドが検証に失敗すると、 ValidationError が発生します。

full_clean()が実行する2番目のステップは、 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()と同様に、モデルの save()メソッドを呼び出しても、モデルのclean()メソッドは呼び出されないことに注意してください。

上記の例では、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に表示されない場合に、フィールド固有の検証エラーを発生させる方法

モデルフォームに表示されないフィールドのModel.clean()で検証エラーを発生させることはできません(フォームはMeta.fieldsまたはMeta.excludeを使用してフィールドを制限する場合があります)。 これを行うと、検証エラーを除外フィールドに関連付けることができないため、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()に似ていますが、個々のフィールド値ではなく、モデルのすべての一意性制約を検証します。 オプションのexclude引数を使用すると、検証から除外するフィールド名のリストを提供できます。 いずれかのフィールドが検証に失敗すると、 ValidationError が発生します。

exclude引数をvalidate_unique()に指定すると、指定したフィールドの1つに関連する unique_together 制約はチェックされないことに注意してください。


オブジェクトの保存

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

Model.save(force_insert=False, force_update=False, using=DEFAULT_DB_ALIAS, update_fields=None)

force_insertおよびforce_update引数の使用の詳細については、 INSERTまたはUPDATE の強制を参照してください。 update_fields引数の詳細については、保存するフィールドの指定セクションを参照してください。

カスタマイズされた保存動作が必要な場合は、このsave()メソッドをオーバーライドできます。 詳細については、事前定義されたモデルメソッドのオーバーライドを参照してください。

モデルの保存プロセスにもいくつかの微妙な点があります。 以下のセクションを参照してください。

主キーの自動インクリメント

モデルに 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ではなくデータベースによって計算されるためです。

便宜上、モデルのフィールドでprimary_key=Trueを明示的に指定しない限り、各モデルにはデフォルトでidという名前の AutoField があります。 詳細については、 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!

見る Djangoが更新することをどのように知っているかvs。 入れる 、以下、これが発生する理由。

自動主キー値を明示的に指定すると、主キーの衝突が発生しないと確信している場合に、オブジェクトを一括保存する場合に最も役立ちます。

PostgreSQLを使用している場合は、主キーに関連付けられているシーケンスを更新する必要がある場合があります。 自動インクリメント主キーの値を手動で指定するを参照してください。


保存するとどうなりますか?

オブジェクトを保存すると、Djangoは次の手順を実行します。

  1. pre-saveシグナルを発行します。 pre_save シグナルが送信され、そのシグナルをリッスンしているすべての関数が何かを実行できるようになります。

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

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

    ほとんどのフィールドはデータの準備を必要としません。 整数や文字列などの単純なデータ型は、Pythonオブジェクトとして「すぐに書き込めます」。 ただし、より複雑なデータ型では、多くの場合、いくつかの変更が必要です。

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

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

  5. 保存後シグナルを発行します。 post_save シグナルが送信され、そのシグナルをリッスンしているすべての関数が何かを実行できるようになります。


Djangoが更新することをどのように知っているかvs。 入れる

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

  • オブジェクトの主キー属性がTrueと評価される値(つまり、Noneまたは空の文字列以外の値)に設定されている場合、DjangoはUPDATEを実行します。
  • オブジェクトの主キー属性が not に設定されている場合、またはUPDATEが何も更新しなかった場合(例: 主キーがデータベースに存在しない値に設定されている場合)、DjangoはINSERTを実行します。

オブジェクトの主キー属性がデフォルトを定義している場合、それが既存のモデルインスタンスであり、主キーがデータベースに存在する値に設定されていれば、DjangoはUPDATEを実行します。 それ以外の場合、DjangoはINSERTを実行します。

ここでの1つの落とし穴は、主キー値が未使用であることを保証できない場合は、新しいオブジェクトを保存するときに主キー値を明示的に指定しないように注意する必要があるということです。 このニュアンスの詳細については、上記の自動主キー値の明示的な指定および以下の INSERTまたはUPDATEの強制を参照してください。

Django 1.5以前では、主キー属性が設定されているときにDjangoはSELECTを実行していました。 SELECTが行を見つけた場合、DjangoはUPDATEを実行しました。それ以外の場合は、INSERTを実行しました。 古いアルゴリズムでは、UPDATEの場合にもう1つのクエリが発生します。 データベースにオブジェクトの主キー値の行が含まれていても、データベースが行の更新を報告しないというまれなケースがあります。 例として、NULLを返すPostgreSQL ON UPDATEトリガーがあります。 このような場合、 select_on_save オプションをTrueに設定することで、古いアルゴリズムに戻すことができます。

INSERTまたはUPDATEを強制する

まれな状況では、 save()メソッドにSQL INSERTを実行させ、UPDATEの実行にフォールバックしないようにする必要があります。 またはその逆:可能であれば更新しますが、新しい行は挿入しません。 このような場合、force_insert=Trueまたはforce_update=Trueパラメーターを save()メソッドに渡すことができます。 両方のパラメーターを渡すとエラーになります。の両方の更新を同時に挿入することはできません。

これらのパラメータを使用する必要があることは非常にまれです。 Djangoはほとんどの場合正しいことを行い、それをオーバーライドしようとすると、追跡が困難なエラーが発生します。 この機能は、高度な使用のみを目的としています。

update_fieldsを使用すると、force_updateと同様に強制的に更新されます。


既存のフィールドに基づいて属性を更新する

現在の値をインクリメントまたはデクリメントするなど、フィールドに対して単純な算術タスクを実行する必要がある場合があります。 これを実現する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があります。 据え置きフィールド値を割り当てまたは変更すると、そのフィールドは更新されたフィールドに追加されます。


オブジェクトの削除

Model.delete(using=DEFAULT_DB_ALIAS, keep_parents=False)

オブジェクトに対してSQL DELETEを発行します。 これにより、データベース内のオブジェクトのみが削除されます。 Pythonインスタンスは引き続き存在し、そのフィールドにデータがあります。 このメソッドは、削除されたオブジェクトの数と、オブジェクトタイプごとの削除数を含むディクショナリを返します。

オブジェクトを一括で削除する方法などの詳細については、オブジェクトの削除を参照してください。

カスタマイズされた削除動作が必要な場合は、delete()メソッドをオーバーライドできます。 詳細については、事前定義されたモデルメソッドのオーバーライドを参照してください。

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


酸洗い物

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

バージョン間で漬物を共有することはできません

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

サイレントに破損したオブジェクトなど、pickleの互換性エラーは診断が難しい場合があるため、pickle化されたバージョンとは異なるDjangoバージョンでモデルの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 '%s %s' % (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__()メソッドは、インスタンスの保存の前後で異なる値を返しますが、__hash__()インスタンスの値はPythonでは禁止されています。


get_absolute_url()

Model.get_absolute_url()

get_absolute_url()メソッドを定義して、オブジェクトの正規URLを計算する方法をDjangoに指示します。 呼び出し元には、このメソッドは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()を使用する場所の1つは、管理アプリです。 オブジェクトがこのメソッドを定義している場合、オブジェクト編集ページには、get_absolute_url()で指定されているように、オブジェクトのパブリックビューに直接ジャンプする「Viewonsite」リンクがあります。

同様に、シンジケーションフィードフレームワークなど、Djangoの他のいくつかのビットは、定義時にget_absolute_url()を使用します。 モデルのインスタンスがそれぞれ一意のURLを持つことが理にかなっている場合は、get_absolute_url()を定義する必要があります。

警告

リンクまたはリダイレクトによるポイズニングの可能性を減らすために、検証されていないユーザー入力からURLを作成することは避けてください。

def get_absolute_url(self):
    return '/%s/' % self.name

self.name'/example.com'の場合、これは'//example.com/'を返します。これは、有効なスキーマ相対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()で一度指定し、他のすべてのコードにその1つの場所を呼び出させます。

ノート

get_absolute_url() must から返される文字列には、ASCII文字(URI仕様で必要な RFC 2396#section-2 )のみが含まれている必要があります。必要に応じて、URLエンコードされます。

get_absolute_url()を呼び出すコードとテンプレートは、それ以上の処理を行わなくても、結果を直接使用できるはずです。 ASCII範囲外の文字を含む文字列を使用している場合は、django.utils.encoding.iri_to_uri()関数を使用してこれを支援することをお勧めします。


追加のインスタンスメソッド

save()delete()に加えて、モデルオブジェクトには次のメソッドが含まれる場合があります。

Model.get_FOO_display()

choices が設定されているすべてのフィールドについて、オブジェクトにはget_FOO_display()メソッドがあります。ここで、FOOはフィールドの名前です。 このメソッドは、フィールドの「人間が読める」値を返します。

例えば:

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'

バージョン3.1で変更: ArrayField および RangeField のサポートが追加されました。


Model.get_next_by_FOO(**kwargs)
Model.get_previous_by_FOO(**kwargs)

null = True を持たない DateField および DateTimeField ごとに、オブジェクトにはget_next_by_FOO()およびget_previous_by_FOO()メソッドがあります。ここで、FOOはフィールドの名前です。 これにより、日付フィールドに関して次および前のオブジェクトが返され、必要に応じて DoesNotExist 例外が発生します。

これらのメソッドは両方とも、モデルのデフォルトマネージャーを使用してクエリを実行します。 カスタムマネージャで使用されるフィルタリングをエミュレートする必要がある場合、または1回限りのカスタムフィルタリングを実行する場合は、どちらのメソッドもオプションのキーワード引数を受け入れます。これは、フィールドルックアップで説明されている形式である必要があります。

日付値が同じ場合、これらのメソッドは主キーをタイブレーカーとして使用することに注意してください。 これにより、レコードがスキップまたは複製されないことが保証されます。 これは、保存されていないオブジェクトに対してこれらのメソッドを使用できないことも意味します。

追加のインスタンスメソッドをオーバーライドする

ほとんどの場合、get_FOO_display()get_next_by_FOO()、およびget_previous_by_FOO()をオーバーライドまたは継承すると期待どおりに機能するはずです。 ただし、これらはメタクラスによって追加されるため、考えられるすべての継承構造を考慮することは現実的ではありません。 より複雑なケースでは、Field.contribute_to_class()をオーバーライドして、必要なメソッドを設定する必要があります。


その他の属性

_state

Model._state

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

ModelStateオブジェクトには、adding、モデルがまだデータベースに保存されていない場合はTrueであるフラグ、およびdb、インスタンスのロード元または保存先のデータベースエイリアスを参照する文字列。

新しくインスタンス化されたインスタンスには、まだ保存されていないため、adding=Truedb=Noneがあります。 QuerySetからフェッチされたインスタンスでは、adding=Falsedbが関連するデータベースのエイリアスに設定されます。