Spec-Zone.ru › Django 4.0

Ссылка на экземпляр модели

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

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

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

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

Нет способа узнать значение ID до вызова save(), так как это значение рассчитывается вашей базой данных, а не Django.

Для удобства каждая модель имеет AutoField с именем id по умолчанию, если вы явно не укажете primary_key=True для поля в вашей модели. Дополнительные сведения см. в документации для 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 определяет 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 используют объект Python datetime для хранения данных. Базы данных не хранят объекты datetime, поэтому значение поля должно быть преобразовано в строку даты в формате ISO для вставки в базу данных.

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

Как Django определяет UPDATE или INSERT

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

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

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

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

>>> from django.db.models import F
>>> product = Product.objects.get(name='Venezuelan Beaver Cheese')
>>> product.number_sold = F('number_sold') + 1
>>> product.save()

Дополнительную информацию см. в документации по F expressions и их использованию в запросах обновления.

Указание полей для сохранения

Если 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 по-прежнему будет существовать и содержать данные в своих полях. Этот метод возвращает количество удалённых объектов и словарь с количеством удалений по каждому типу объекта.

Дополнительную информацию, включая удаление объектов в пакетном режиме, см. в Удаление объектов.

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

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

Сериализация объектов

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

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

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

Поскольку ошибки совместимости сериализованных данных могут быть трудно диагностированы, например, при молчаливом повреждении объектов, будет выброшено исключение 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() — в приложении администрирования. Если объект определяет этот метод, страница редактирования объекта будет иметь ссылку «Просмотр на сайте», которая переведёт вас напрямую к публичному представлению объекта, как указано в 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() и заставьте весь ваш код вызывать это место.

END_OF_DOCUMENT_MARKER

Примечание

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

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/4.0/ref/models/instances/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API