Spec-Zone.ru › Django 3.0

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

В этом документе описываются детали API 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)

Если вы хотите настроить поведение сохранения, вы можете переопределить этот 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, но вы хотите явно определить 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.

Изменено в Django 3.0:

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

Принудительное выполнение INSERT или UPDATE

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

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

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

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

Иногда вам нужно выполнить простое арифметическое действие над полем, например, инкрементировать или декрементировать текущее значение. Очевидный способ достижения этого – сделать что-то вроде:

>>> 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. Сериализованные объекты не следует использовать в качестве стратегии долгосрочного архивирования.

Поскольку ошибки совместимости сериализованных объектов могут быть трудно диагностируемы, например, молча повреждённые объекты, при попытке десериализации модели в версии Django, отличной от той, в которой она была сериализована, будет вызвано исключение 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() для указания 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.views.details', args=[str(self.id)])

Одно из мест, где 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() и заставьте весь остальной код обращаться к этому одному месту.

Примечание

Строка, которую вы возвращаете из 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'
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/3.0/ref/models/instances/

Spec-Zone.ru

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