Справочник по методам модели

Этот документ описывает детали API Model. Он основан на материале, представленном в руководствах model и запрос к базе данных, так что вы, вероятно, захотите прочитать и понять эти документы, прежде чем читать этот.

В этом справочнике мы будем использовать пример моделей Weblog’а, представленный в руководстве по запросам к базе данных.

Создание объектов

Чтобы создать новый экземпляр модели, создайте его экземпляр, как и любой другой класс Python:

class Model(**kwargs)[исходный код]

Ключевыми аргументами являются просто имена полей, которые вы определили в вашей модели. Обратите внимание, что создание экземпляра модели никоим образом не затрагивает вашу базу данных; для этого вам необходимо выполнить save().

Примечание

Вы можете испытать желание изменить модель, переопределив метод __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 содержит имена всех загруженных полей, а values содержит загруженные значения для каждого поля в field_names. field_names находятся в том же порядке, что и values. Если присутствуют все поля модели, то values гарантированно будут в том порядке, в котором их ожидает __init__(). То есть экземпляр может быть создан с помощью cls(* values). Если какие-либо поля отложены, они не появятся в field_names. В этом случае присвойте значение django.db.models.DEFERRED каждому из пропущенных полей.

Помимо создания новой модели, метод from_db() должен установить флаги adding и db в атрибуте _state нового экземпляра.

Ниже приведен пример, показывающий, как записать начальные значения полей, загружаемых из базы данных:

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(), чтобы прояснить, как это делается. В этом случае, конечно, можно было бы просто использовать вызов super() в методе from_db().

Обновление объектов из базы данных

Если вы удаляете поле из экземпляра модели, при повторном доступе к нему значение из базы данных снова загружается:

>>> 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()[исходный код]

Вспомогательный метод, который возвращает набор, содержащий имена атрибутов всех тех полей, которые в данный момент откладываются для этой модели.

Проверка объектов

Существует три этапа проверки модели:

  1. Проверка полей модели - Model.clean_fields()
  2. Проверка модели полностью - Model.clean()
  3. Проверка уникальности полей - Model.validate_unique()

Все три шага выполняются при вызове метода модели full_clean().

Когда вы используете ModelForm, вызов is_valid() выполнит эти шаги проверки для всех полей, включенных в форму. Смотрите документацию ModelForm для получения дополнительной информации. Вам нужно только вызывать метод модели full_clean(), если вы планируете самостоятельно обрабатывать ошибки проверки или если вы исключили поля из ModelForm, для которых требуется проверка.

Model.full_clean(exclude=None, validate_unique=True)[исходный код]

Этот метод вызывает Model.clean_fields(), Model.clean() и Model.validate_unique() (если validate_unique равно True), в этом порядке и вызывает ValidationError, который имеет атрибут message_dict, содержащий ошибки всех трех этапов.

Необязательный аргумент exclude может использоваться для предоставления списка имен полей, которые можно исключить из проверки и очистки. ModelForm использует этот аргумент, чтобы исключить проверку полей, которые отсутствуют в вашей форме, поскольку любые возникшие ошибки не могут быть исправлены пользователем.

Обратите внимание, что full_clean() не будет автоматически вызываться при вызове метода модели save(). Вам нужно будет вызвать его вручную, если вы хотите запустить одноэтапную проверку моделей для ваших собственных моделей, созданных вручную. Например:

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(), заключается в вызове 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().

В приведенном выше примере исключение ValidationError, вызванное Model.clean(), было создано со строкой, поэтому оно будет сохранено в специальном ключе словаря ошибок 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(), любое ограничение 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(), потому что это значение рассчитывается вашей базой данных, а не Django.

Для удобства каждая модель имеет AutoField с именем id по умолчанию, если вы явно не укажете primary_key=True для поля в вашей модели. Смотрите документацию для AutoField для получения более подробной информации.

Свойство pk

Model.pk

Независимо от того, определяете ли вы поле первичного ключа самостоятельно или позволяете Django предоставить его для вас, каждая модель будет иметь свойство, называемое pk. Он ведет себя как обычный атрибут в модели, но на самом деле является псевдонимом для любого атрибута, являющегося полем первичного ключа для модели. Вы можете прочитать и установить это значение, как и для любого другого атрибута, и он обновит правильное поле в модели.

Явное указание значений авто-первичного ключа

Если модель имеет AutoField, но вы хотите явно определить идентификатор нового объекта при сохранении, просто определите его явно перед сохранением, а не полагайтесь на автоматическое назначение идентификатора:

>>> 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 определяет UPDATE или INSERT» ниже, по той причине, по которой это происходит.

Явное указание значений авто-первичного ключа в основном полезно для массового сохранения объектов, когда вы уверены, что у вас не будет коллизии первичного ключа.

Если вы используете PostgreSQL, возможно, потребуется обновить последовательность, связанную с первичным ключом; смотрите Ручное указание значений автоинкрементных первичных ключей.

Что происходит, когда вы сохраняете?

Когда вы сохраняете объект, Django выполняет следующие шаги:

  1. Посылает сигнал предварительного сохранения pre-save. Передается сигнал pre_save, позволяющий функциям, прослушивающим этот сигнал, что-то делать.

  2. Предварительная обработка данных. Каждый метод поля pre_save() вызывается для выполнения любой необходимой автоматической модификации данных. Например, поля даты/времени переопределяют pre_save() для реализации auto_now_add и auto_now.

  3. Подготовка данных для базы данных. Метод каждого поля get_db_prep_save() должен предоставить свое текущее значение в виде данных, которые можно записать в базу данных.

    Большинство полей не требуют подготовки данных. Простые типы данных, такие как целые числа и строки, «готовы к записи» в виде объекта Python. Однако более сложные типы данных часто требуют некоторой модификации.

    Например, поля DateField используют объект datetime Python для хранения данных. Базы данных не хранят объекты datetime, поэтому значение поля должно быть преобразовано в ISO-совместимую строку даты для вставки в базу данных.

  4. Вставка данных в базу данных. Предварительно обработанные, подготовленные данные составляются в оператор SQL для вставки в базу данных.

  5. Посылает сигнал post-save после сохранения. Передается сигнал post_save, позволяющий любым функциям, прослушивающим этот сигнал, что-то делать.

Как Django узнает, когда использовать UPDATE или INSERT

Возможно, вы заметили, что объекты базы данных Django используют один и тот же метод save() для создания и изменения объектов. Django абстрагируется от необходимости использовать операторы INSERT или UPDATE. В частности, когда вы вызываете save() и атрибут первичного ключа объекта не определяет default, Django следует этому алгоритму:

  • Если для атрибута первичного ключа объекта установлено значение, которое оценивается как True (т.е. значение, отличное от None или пустой строки), Django выполняет UPDATE.
  • Если атрибут первичного ключа объекта не установлен или если UPDATE ничего не обновил (например, если первичному ключу присвоено значение, которого нет в базе данных), Django выполняет INSERT.

Если атрибут первичного ключа объекта определяет default, тогда Django выполняет UPDATE, если это существующий экземпляр модели и первичный ключ имеет значение, которое существует в базе данных. В противном случае Django выполняет INSERT.

Единственное, что здесь нужно сделать, это то, что вы должны быть осторожны, чтобы не указывать значение первичного ключа явно при сохранении новых объектов, если вы не можете гарантировать, что значение первичного ключа не используется. Подробнее об этом нюансе смотрите в разделе Explicitly specifying auto-primary-key values и Форсирование INSERT или UPDATE ниже.

В Django 1.5 и более ранних версиях Django сделал SELECT, когда был установлен атрибут первичного ключа. Если SELECT нашел строку, то Django сделал UPDATE, в противном случае он сделал INSERT. Старый алгоритм приводит к еще одному запросу в случае UPDATE. В некоторых редких случаях база данных не сообщает, что строка была обновлена, даже если база данных содержит строку для значения первичного ключа объекта. Примером является триггер PostgreSQL ON UPDATE, который возвращает NULL. В таких случаях можно вернуться к старому алгоритму, установив параметр select_on_save в True.

INSERT или UPDATE

В некоторых редких случаях необходимо иметь возможность заставить метод save() выполнять SQL INSERT и не отступать от выполнения UPDATE. Или наоборот: обновите, если это возможно, но не вставляйте новую строку. В этих случаях вы можете передать параметры force_insert=True или force_update=True методу save(). Очевидно, что передача обоих параметров является ошибкой: вы не можете одновременно вставлять и обновлять!

Это должно быть очень редко, что вам нужно будет использовать эти параметры. Django почти всегда делает правильные вещи, и попытка переопределить это приведет к ошибкам, которые трудно отследить. Эта функция предназначена только для расширенного использования.

Использование update_fields приведет к обновлению аналогично force_update.

Обновление атрибутов на основе существующих полей

Иногда вам нужно выполнить простую арифметическую задачу в поле, например, увеличить или уменьшить текущее значение. Одним из способов достижения этого является выполнение арифметики в 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, будут обновлены только поля, названные в этом списке. Это может быть желательно, если вы хотите обновить только одно или несколько полей объекта. Отказ от обновления всех полей модели в базе данных приведет к небольшому выигрышу в производительности. Например:

product.name = 'Name changed again'
product.save(update_fields=['name'])

Аргумент update_fields может быть любым итеративным, содержащим строки. Пустая итерация update_fields пропустит сохранение. Значение None обновит все поля.

Указание update_fields приведет к обновлению.

При сохранении модели, полученной с помощью отложенной загрузки модели (only() или defer()) обновляются только поля, загруженные из БД. По сути, в этом случае происходит автоматическое update_fields. Если вы назначите или измените какое-либо значение отложенного поля, поле будет добавлено в обновленные поля.

Удаление объектов

Model.delete(using=DEFAULT_DB_ALIAS, keep_parents=False)[исходный код]

Выдает SQL DELETE для объекта. Это только удаляет объект в базе данных; Экземпляр Python все еще будет существовать и все еще будет содержать данные в своих полях. Этот метод возвращает количество удаленных объектов и словарь с количеством удалений на тип объекта.

Для получения более подробной информации, в том числе о том, как массово удалять объекты, смотрите themes-db-query-delete.

Если вам нужно индивидуальное поведение удаления, вы можете переопределить метод delete(). Смотрите Переопределение методов модели для более подробной информации.

Иногда с помощью наследование от нескольких таблиц вы можете удалить только данные дочерней модели. Указание keep_parents=True сохранит данные родительской модели.

Упаковывание объектов

Когда вы pickle модель, ее текущее состояние сохраняется. Когда вы откроете его, он будет содержать экземпляр модели в тот момент, когда он был выбран, а не данные, которые в данный момент находятся в базе данных.

Вы не можете использовать pickle между версиями

Упакованные модели действительны только для той версии Django, которая использовалась для их генерации. Если вы генерируете pickle с использованием Django версии N, нет никакой гарантии, что pickle будет читаться с Django версии N+1. pickle не должны использоваться как часть долгосрочной архивной стратегии.

Так как ошибки совместимости с pickle могут быть трудно диагностируемыми, например, незаметно поврежденные объекты, возникает «RuntimeWarning», когда вы пытаетесь распаковать модель в версии Django, отличной от той, в которой она была упакована.

Другие методы экземпляра модели

Несколько методов объекта имеют специальные цели.

__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(), чтобы сообщить Django, как рассчитать канонический 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() в приложении администратора. Если объект определяет этот метод, страница редактирования объекта будет иметь ссылку «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/', который, в свою очередь, является действительным URL-адресом схемы, но не ожидаемым '/%2Fexample.com/'.

Хорошей практикой является использование get_absolute_url() в шаблонах вместо жесткого кодирования 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() и пусть весь ваш другой код вызывает только его.

Примечание

Строка, которую вы возвращаете из get_absolute_url() должна содержать только символы ASCII (требуется спецификацией URI RFC 2396#section-2) и быть при необходимости закодированной в URL.

Код и шаблоны, вызывающие get_absolute_url(), должны иметь возможность использовать результат напрямую без какой-либо дальнейшей обработки. Вы можете использовать функцию django.utils.encoding.iri_to_uri(), чтобы помочь с этим, если вы используете строки, содержащие символы вне диапазона ASCII.

Дополнительные методы экземпляра

В дополнение к 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'
Changed in Django 3.1:

Добавлена поддержка ArrayField и RangeField.

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

Для каждого DateField и DateTimeField, которые не имеют null=True, объект будет иметь методы get_next_by_FOO() и get_previous_by_FOO(), где FOO - это имя поля. Это возвращает следующий и предыдущий объект относительно поля даты, вызывая исключение DoesNotExist, когда это необходимо.

Оба эти метода будут выполнять свои запросы с использованием менеджера по умолчанию для модели. Если вам нужно эмулировать фильтрацию, используемую настраиваемым менеджером, или вы хотите выполнить одноразовую настраиваемую фильтрацию, оба метода также принимают необязательные ключевые аргументы, которые должны иметь формат, описанный в Поиск по полям.

Обратите внимание, что в случае идентичных значений даты эти методы будут использовать первичный ключ в качестве прерывателя связей. Это гарантирует, что никакие записи не будут пропущены или дублированы. Это также означает, что вы не можете использовать эти методы на несохраненных объектах.

Переопределение дополнительных методов экземпляра

В большинстве случаев переопределение или наследование 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=True и db=None, поскольку они еще не сохранены. Экземпляры, полученные из QuerySet, будут иметь adding=False и db в качестве псевдонима связанной базы данных.

Вернуться на верх