Ссылка на экземпляр модели
В этом документе описываются подробности API Model. Он основан на материалах, представленных в руководствах по моделям и запросам к базе данных, поэтому вам, вероятно, стоит прочитать и понять эти документы перед чтением этого.
В этом руководстве мы будем использовать представленные в руководстве по запросам к базе данных примеры моделей блога.
Создание объектов
Для создания нового экземпляра модели, инициализируйте его как любой другой класс Python:
-
class Model(**kwargs)[source]
Ключевые аргументы — это имена полей, которые вы определили в своей модели. Обратите внимание, что инициализация модели никак не затрагивает вашу базу данных; для этого вам нужно save().
Примечание
Вы можете захотеть настроить модель, переопределяя метод __init__. Однако, будьте осторожны, чтобы не менять сигнатуру вызова, так как любое изменение может помешать сохранению экземпляра модели. Кроме того, ссылка на поля модели в __init__ в некоторых случаях может привести к ошибкам бесконечной рекурсии. Вместо переопределения __init__, попробуйте использовать один из этих подходов:
-
Добавьте метод класса к классу модели:
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") -
Добавьте метод к пользовательскому менеджеру (обычно предпочтительно):
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)[source]
Метод 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, **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(**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, from_queryset=None)[source]
-
Model.arefresh_from_db(using=None, fields=None, from_queryset=None)
Асинхронная версия: arefresh_from_db()
Если вам нужно перезагрузить значения модели из базы данных, вы можете использовать метод refresh_from_db(). При вызове этого метода без аргументов выполняется следующее:
- Все поля модели, не отмеченные как отложенные, обновляются до значений, присутствующих в базе данных в данный момент.
- Любые кэшированные отношения очищаются из перезагруженного экземпляра.
Перезагружаются только поля модели. Другие зависящие от базы данных значения, такие как аннотации, не перезагружаются. Также не очищаются атрибуты @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)
Аргумент from_queryset позволяет использовать другой набор запросов, отличный от созданного из _base_manager. Это даёт вам больший контроль над тем, как модель перезагружается. Например, когда ваша модель использует мягкое удаление, можно заставить refresh_from_db() учитывать это:
obj.refresh_from_db(from_queryset=MyModel.active_objects.all())
Вы можете кешировать связанные объекты, которые в противном случае были бы очищены из перезагруженного экземпляра:
obj.refresh_from_db(from_queryset=MyModel.objects.select_related("related_field"))
Вы можете заблокировать строку до конца транзакции перед перезагрузкой значений модели:
obj.refresh_from_db(from_queryset=MyModel.objects.select_for_update())
Добавлен аргумент from_queryset.
-
Model.get_deferred_fields()[source]
Вспомогательный метод, возвращающий множество имён атрибутов всех полей, которые в настоящее время отложены для данной модели.
Валидация объектов
Валидация модели включает четыре этапа:
- Валидация полей модели -
Model.clean_fields() - Валидация модели в целом -
Model.clean() - Валидация уникальности полей -
Model.validate_unique() - Валидация ограничений -
Model.validate_constraints()
Все четыре этапа выполняются при вызове метода full_clean() модели.
При использовании ModelForm, вызов is_valid() выполнит эти этапы валидации для всех полей, включённых в форму. Подробнее см. документацию по ModelForm. Вам следует вызвать метод full_clean() модели только если планируете самостоятельно обрабатывать ошибки валидации или если вы исключили поля из ModelForm, которые требуют валидации.
-
Model.full_clean(exclude=None, validate_unique=True, validate_constraints=True)[source]
Этот метод вызывает 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() — это очистка каждого отдельного поля.
-
Model.clean_fields(exclude=None)[source]
Этот метод проверит все поля вашей модели. Необязательный аргумент exclude позволяет указать set имён полей, которые следует исключить из проверки. Он поднимет исключение ValidationError, если какое-либо поле не пройдёт проверку.
Вторым шагом full_clean() является вызов Model.clean(). Этот метод следует переопределять для выполнения пользовательской валидации вашей модели.
-
Model.clean()[source]
Этот метод следует использовать для предоставления пользовательской валидации модели и изменения атрибутов вашей модели при необходимости. Например, вы можете использовать его для автоматического заполнения значения поля или для валидации, требующей доступа к нескольким полям:
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)[source]
Этот метод аналогичен 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() проверит все остальные ограничения вашей модели.
-
Model.validate_constraints(exclude=None)[source]
Этот метод проверяет все ограничения, определённые в Meta.constraints. Необязательный аргумент exclude позволяет указать set имён полей, которые следует исключить из проверки. Он поднимет исключение ValidationError, если какое-либо ограничение не пройдёт проверку.
Сохранение объектов
Чтобы сохранить объект обратно в базу данных, вызовите save():
-
Model.save(*, force_insert=False, force_update=False, using=DEFAULT_DB_ALIAS, update_fields=None)[source]
-
Model.asave(*, force_insert=False, force_update=False, using=DEFAULT_DB_ALIAS, update_fields=None)
Асинхронная версия: asave()
Подробности использования аргументов force_insert и force_update см. в разделе Принудительное выполнение INSERT или UPDATE. Подробности о параметре update_fields можно найти в разделе Указание полей для сохранения.
Если вы хотите настроить поведение сохранения, вы можете переопределить этот save() метод. Подробнее см. в разделе Переопределение предопределённых методов модели.
Процесс сохранения модели также имеет некоторые нюансы; см. разделы ниже.
Устарело начиная с версии 5.1: Поддержка позиционных аргументов устарела.
Автоинкрементируемые первичные ключи
Если модель имеет 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 выполняет следующие шаги:
-
Отправка сигнала pre-save. Отправляется сигнал
pre_save, позволяя всем функциям, подписчикам на этот сигнал, выполнить какие-либо действия. -
Предварительная обработка данных. Вызывается метод
pre_save()каждого поля для выполнения необходимых автоматических изменений данных. Например, поля даты/времени переопределяютpre_save()для реализацииauto_now_addиauto_now. -
Подготовка данных для базы данных. От каждого поля запрашивается метод
get_db_prep_save(), чтобы предоставить его текущее значение в типе данных, который может быть записан в базу данных.Большинству полей не требуется подготовка данных. Простые типы данных, такие как целые числа и строки, «готовы к записи» как объект Python. Однако более сложные типы данных часто требуют некоторой модификации.
Например, поля
DateFieldиспользуют объект Pythondatetime, для хранения данных. Базы данных не хранят объектыdatetime, поэтому значение поля должно быть преобразовано в строку даты в формате ISO для вставки в базу данных. - Вставка данных в базу данных. Подготовленные данные составляют SQL-запрос для вставки в базу данных.
-
Отправка сигнала post-save. Отправляется сигнал
post_save, позволяя всем функциям, подписчикам на этот сигнал, выполнить какие-либо действия.
Как Django определяет UPDATE или INSERT
Возможно, вы заметили, что объекты базы данных Django используют один и тот же метод save() для создания и изменения объектов. Django абстрагирует необходимость использования INSERT или UPDATE SQL-запросов. В частности, при вызове save() и атрибут первичного ключа объекта не определяет default или db_default, Django следует этому алгоритму:
- Если атрибут первичного ключа объекта установлен на значение, которое оценивается как
True(то есть, значение, отличное отNoneили пустой строки), Django выполняетUPDATE. - Если атрибут первичного ключа объекта не установлен или если
UPDATEничего не изменило (например, если первичный ключ установлен на значение, которое не существует в базе данных), Django выполняетINSERT.
Если атрибут первичного ключа объекта определяет default или db_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.
Добавлен параметр Field.db_default.
Принудительное выполнение INSERT или UPDATE
В некоторых редких случаях необходимо иметь возможность принудительно заставить метод save() выполнить SQL INSERT, а не перейти к выполнению UPDATE. Или наоборот: обновить, если возможно, но не вставлять новую строку. В таких случаях можно передать параметры force_insert=True или force_update=True методу save(). Передача обоих параметров является ошибкой: нельзя одновременно вставить и обновить!
При использовании наследования от нескольких таблиц также можно передать кортеж родительских классов методу force_insert для принудительного выполнения INSERT заявлений для каждого родителя. Например:
Restaurant(pk=1, name="Bob's Cafe").save(force_insert=(Place,)) Restaurant(pk=1, name="Bob's Cafe", rating=4).save(force_insert=(Place, Rating))
Можно передать force_insert=(models.Model,) для принудительного выполнения INSERT заявления для всех родителей. По умолчанию, force_insert=True только принудительно вставляет новую строку для текущей модели.
В большинстве случаев вам не нужно будет использовать эти параметры. Django практически всегда сделает всё правильно, а попытка переопределения может привести к ошибкам, которые трудно отследить. Эта возможность предназначена только для продвинутых пользователей.
Использование update_fields аналогично принудительно выполнит обновление force_update.
Добавлена поддержка передачи кортежа родительских классов методу force_insert.
Обновление атрибутов на основе существующих полей
Иногда вам нужно выполнить простое арифметическое действие над полем, например, инкрементировать или декрементировать текущее значение. Один из способов достижения этого — выполнить арифметику в 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. Если вы присваиваете или изменяете значение любого отложенного поля, поле будет добавлено к обновляемым полям.
Field.pre_save() и update_fields
Если update_fields передается, вызываются только методы pre_save() полей update_fields. Например, это означает, что поля даты/времени с auto_now=True не будут обновлены, если они не включены в update_fields.
Удаление объектов
-
Model.delete(using=DEFAULT_DB_ALIAS, keep_parents=False)[source]
-
Model.adelete(using=DEFAULT_DB_ALIAS, keep_parents=False)
Асинхронная версия: adelete()
Выполняет SQL DELETE для объекта. Это удаляет объект только в базе данных; экземпляр Python по-прежнему будет существовать и содержать данные в своих полях, за исключением первичного ключа, установленного в None. Этот метод возвращает количество удаленных объектов и словарь с количеством удалений по типу объектов.
Для получения более подробной информации, включая способ удаления объектов группами, см. Удаление объектов.
Если вам требуется настройка поведения удаления, вы можете переопределить метод delete(). Дополнительные сведения см. в разделе Переопределение предопределенных методов модели.
Иногда при наследовании от нескольких таблиц вам может потребоваться удалить только данные дочерней модели. Указание keep_parents=True сохранит данные родительской модели.
Сериализация объектов
При pickle модели, ее текущее состояние сериализуется. При десериализации она будет содержать экземпляр модели на момент сериализации, а не данные, которые в настоящее время находятся в базе данных.
Другие методы экземпляра модели
Несколько методов объекта имеют особые цели.
__str__()
-
Model.__str__()[source]
Метод __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 f"{self.first_name} {self.last_name}"
__eq__()
-
Model.__eq__()[source]
Метод равенства определен таким образом, что экземпляры с одинаковым значением первичного ключа и тем же конкретным классом считаются равными, за исключением того, что экземпляры с значением первичного ключа 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__()[source]
Метод __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 3986#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/5.1/ref/models/instances/