Spec-Zone.ru › Django 4.1

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

В данном документе описаны детали 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, (value for value in values if value is not DEFERRED))
    )
    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()
  4. Валидация ограничений - Model.validate_constraints()

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

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

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

В более старых версиях ограничения не проверялись во время валидации модели.

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

Этот метод вызывает Model.clean_fields(), Model.clean(), Model.validate_unique() (если validate_unique равно True) и Model.validate_constraints() (если validate_constraints равно 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() — очистка каждого отдельного поля.

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

Добавлен аргумент validate_constraints.

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

Значение exclude теперь преобразуется в set, а не в list.

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(), но проверяет ограничения уникальности, определенные с помощью Field.unique, Field.unique_for_date, Field.unique_for_month, Field.unique_for_year или Meta.unique_together в вашей модели, а не отдельных значений полей. Необязательный аргумент exclude позволяет указать set имен полей, которые следует исключить из валидации. Он поднимет исключение ValidationError, если какая-либо валидация полей завершится ошибкой.

UniqueConstraint, определенные в Meta.constraints, проверяются с помощью Model.validate_constraints().

Обратите внимание, что если вы предоставите аргумент exclude методу validate_unique(), любое ограничение unique_together, включающее одно из предоставленных вами полей, не будет проверено.

Наконец, full_clean() проверит все остальные ограничения вашей модели.

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

В более старых версиях UniqueConstraint проверялись с помощью validate_unique().

Model.validate_constraints(exclude=None)
Добавлена в Django 4.1.

Этот метод проверяет все ограничения, определенные в Meta.constraints. Необязательный аргумент exclude позволяет указать set имен полей, которые следует исключить из валидации. Он поднимет исключение ValidationError, если какая-либо проверка ограничений завершится ошибкой.

Сохранение объектов

Чтобы сохранить объект в базе данных, вызовите 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 отправляется, что позволяет любым функциям, подписка на этот сигнал, выполнить какие-либо действия.
  2. Предварительная обработка данных. Метод pre_save() каждого поля вызывается для выполнения любых необходимых автоматических изменений данных. Например, поля даты/времени переопределяют pre_save() для реализации auto_now_add и auto_now.
  3. Подготовьте данные для базы данных. Метод get_db_prep_save() каждого поля запрашивается, чтобы предоставить его текущее значение в типе данных, который может быть записан в базу данных.

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

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

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

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

Вы, возможно, заметили, что объекты базы данных Django используют тот же метод save() для создания и изменения объектов. Django абстрагирует необходимость использовать операторы SQL INSERT или UPDATE. В частности, при вызове 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. Сериализованные объекты не следует использовать в качестве части долгосрочной стратегии архивации.

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

Примечание

Строка, возвращаемая из 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/4.1/ref/models/instances/

Spec-Zone.ru

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