Справочник по методам модели¶
Этот документ описывает детали API Model
. Он основан на материале, представленном в руководствах model и :doc: запрос к базе данных </topics/db/queries>, так что вы, вероятно, захотите прочитать и понять эти документы, прежде чем читать этот.
Во всем этом справочнике мы будем использовать example blog models, представленные в database query guide.
Создание объектов¶
Чтобы создать новый экземпляр модели, создайте его экземпляр, как и любой другой класс Python:
-
class
Model
(**kwargs)[исходный код]¶
Ключевыми аргументами являются просто имена полей, которые вы определили в вашей модели. Обратите внимание, что создание экземпляра модели никоим образом не затрагивает вашу базу данных; для этого вам необходимо выполнить 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)[исходный код]¶
Метод 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)[исходный код]¶
-
Model.
arefresh_from_db
(using=None, fields=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)
-
Model.
get_deferred_fields
()[исходный код]¶
Вспомогательный метод, который возвращает набор, содержащий имена атрибутов всех тех полей, которые в данный момент откладываются для этой модели.
Добавлен метод arefresh_from_db()
.
Проверка объектов¶
В проверке модели участвуют четыре этапа:
- Проверка полей модели -
Model.clean_fields()
- Проверка модели полностью -
Model.clean()
- Проверка уникальности полей -
Model.validate_unique()
- Проверьте ограничения -
Model.validate_constraints()
.
Все четыре шага выполняются при вызове метода модели full_clean()
.
Когда вы используете ModelForm
, вызов is_valid()
выполнит эти шаги проверки для всех полей, включенных в форму. Смотрите документацию ModelForm для получения дополнительной информации. Вам нужно только вызывать метод модели full_clean()
, если вы планируете самостоятельно обрабатывать ошибки проверки или если вы исключили поля из ModelForm
, для которых требуется проверка.
Предупреждение
Ограничения, содержащие JSONField
, могут не вызывать ошибок валидации, поскольку преобразования ключей, индексов и путей имеют много специфических для базы данных оговорок. Это may be fully supported later.
Вы всегда должны проверять, что в журнале django.db.models
нет сообщений типа «Got a database error calling check() on … « для подтверждения правильности проверки.
-
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
можно использовать для предоставления set
имен полей, которые могут быть исключены из проверки и очистки. 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
позволяет вам указать set
имен полей, которые нужно исключить из проверки. Метод выдаст сообщение 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
s, определенные в Meta.constraints
, подтверждаются Model.validate_constraints()
.
Обратите внимание, что если вы предоставите аргумент exclude
для validate_unique()
, любое ограничение unique_together
, включающее одно из предоставленных вами полей, проверяться не будет.
Наконец, full_clean()
проверит любые другие ограничения на вашу модель.
-
Model.
validate_constraints
(exclude=None)[исходный код]¶
Этот метод проверяет все ограничения, определенные в Meta.constraints
. Необязательный аргумент exclude
позволяет вам указать set
имен полей, которые нужно исключить из проверки. Метод выдаст сообщение ValidationError
, если какие-либо ограничения не прошли проверку.
Сохранение объектов¶
Чтобы сохранить объект обратно в базу данных, вызовите save()
:
-
Model.
save
(force_insert=False, force_update=False, using=DEFAULT_DB_ALIAS, update_fields=None)[исходный код]¶
-
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()
. Смотрите Переопределение методов модели для более подробной информации.
Процесс сохранения модели также имеет некоторые тонкости; см. разделы ниже.
Добавлен метод asave()
.
Автоинкрементные первичные ключи¶
Если модель имеет AutoField
- автоинкрементный первичный ключ, то это автоинкрементное значение будет вычислено и сохранено как атрибут объекта при первом вызове save()
:
>>> b2 = Blog(name="Cheddar Talk", tagline="Thoughts on cheese.")
>>> b2.id # Returns None, because b2 doesn't have an ID yet.
>>> b2.save()
>>> b2.id # Returns the ID of your new object.
Невозможно определить, какое значение идентификатора будет перед вызовом save()
, потому что это значение рассчитывается вашей базой данных, а не Django.
Для удобства каждая модель имеет AutoField
с именем id
по умолчанию, если вы явно не укажете primary_key=True
для поля в вашей модели. Смотрите документацию для AutoField
для получения более подробной информации.
Свойство pk
¶
-
Model.
pk
¶
Независимо от того, определяете ли вы поле первичного ключа самостоятельно или позволяете Django предоставить его для вас, каждая модель будет иметь свойство, называемое pk
. Он ведет себя как обычный атрибут в модели, но на самом деле является псевдонимом для любого атрибута, являющегося полем первичного ключа для модели. Вы можете прочитать и установить это значение, как и для любого другого атрибута, и он обновит правильное поле в модели.
Явное указание значений авто-первичного ключа¶
Если модель имеет AutoField
, но вы хотите явно определить идентификатор нового объекта при сохранении, задайте его явно перед сохранением, а не полагайтесь на автоматическое присвоение идентификатора:
>>> b3 = Blog(id=3, name="Cheddar Talk", tagline="Thoughts on cheese.")
>>> b3.id # Returns 3.
>>> b3.save()
>>> b3.id # Returns 3.
Если вы назначаете значения авто-первичного ключа вручную, убедитесь, что вы не используете уже существующее значение первичного ключа! Если вы создаете новый объект с явным значением первичного ключа, который уже существует в базе данных, Django будет предполагать, что вы изменяете существующую запись, а не создаете новую.
Учитывая приведенный выше пример блога 'Cheddar Talk'
, этот пример переопределяет предыдущую запись в базе данных:
b4 = Blog(id=3, name="Not Cheddar", tagline="Anything but cheese.")
b4.save() # Overrides the previous blog with ID=3!
Посмотрите, как Django знает, чтобы ОБНОВИТЬ против INSERT ниже, по той причине, по которой это происходит.
Явное указание значений авто-первичного ключа в основном полезно для массового сохранения объектов, когда вы уверены, что у вас не будет коллизии первичного ключа.
Если вы используете PostgreSQL, возможно, потребуется обновить последовательность, связанную с первичным ключом; смотрите Ручное указание значений автоинкрементных первичных ключей.
Что происходит, когда вы сохраняете?¶
Когда вы сохраняете объект, Django выполняет следующие шаги:
Посылает сигнал предварительного сохранения pre-save. Передается сигнал
pre_save
, позволяющий функциям, прослушивающим этот сигнал, что-то делать.Предварительная обработка данных. Каждый метод поля
pre_save()
вызывается для выполнения любой необходимой автоматической модификации данных. Например, поля даты/времени переопределяютpre_save()
для реализацииauto_now_add
иauto_now
.Подготовка данных для базы данных. Метод каждого поля
get_db_prep_save()
должен предоставить свое текущее значение в виде данных, которые можно записать в базу данных.Большинство полей не требуют подготовки данных. Простые типы данных, такие как целые числа и строки, «готовы к записи» в виде объекта Python. Однако более сложные типы данных часто требуют некоторой модификации.
Например, поля
DateField
используют объектdatetime
Python для хранения данных. Базы данных не хранят объекты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()
. Очевидно, что передача обоих параметров является ошибкой: вы не можете одновременно вставлять и обновлять!
При использовании multi-table inheritance можно также предоставить кортеж родительских классов для 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 будет записано обратно в базу данных.
Этот процесс можно сделать более надежным, avoiding a race condition, а также несколько ускорить, если выразить обновление относительно исходного значения поля, а не как явное присвоение нового значения. Для выполнения такого рода относительного обновления в 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 выражениям
и их использование в запросах на обновление.
Указание полей для сохранения¶
Если в 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)[исходный код]¶
-
Model.
adelete
(using=DEFAULT_DB_ALIAS, keep_parents=False)[исходный код]¶
Асинхронная версия: adelete()
Выдает SQL DELETE
для объекта. При этом удаляется только объект в базе данных; экземпляр Python по-прежнему будет существовать и содержать данные в своих полях, за исключением первичного ключа, установленного в значение None
. Этот метод возвращает количество удаленных объектов и словарь с количеством удалений по типам объектов.
Для получения более подробной информации, в том числе о том, как массово удалять объекты, смотрите themes-db-query-delete.
Если вам нужно индивидуальное поведение удаления, вы можете переопределить метод delete()
. Смотрите Переопределение методов модели для более подробной информации.
Иногда с помощью наследование от нескольких таблиц вы можете удалить только данные дочерней модели. Указание keep_parents=True
сохранит данные родительской модели.
Был добавлен метод adelete()
.
Упаковывание объектов¶
Когда вы pickle
модель, ее текущее состояние сохраняется. Когда вы откроете его, он будет содержать экземпляр модели в тот момент, когда он был выбран, а не данные, которые в данный момент находятся в базе данных.
Другие методы экземпляра модели¶
Несколько методов объекта имеют специальные цели.
__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 f"{self.first_name} {self.last_name}"
__eq__()
¶
-
Model.
__eq__
()[исходный код]¶
Метод равенства определен так, что экземпляры с одинаковым значением первичного ключа и одним и тем же конкретным классом считаются равными, за исключением того, что экземпляры со значением первичного ключа None
не равны ничему, кроме самих себя. Для прокси-моделей конкретный класс определяется как первый непрокси-родитель модели; для всех остальных моделей это просто класс модели.
Например:
from django.db import models
class MyModel(models.Model):
id = models.AutoField(primary_key=True)
class MyProxyModel(MyModel):
class Meta:
proxy = True
class MultitableInherited(MyModel):
pass
# Primary keys compared
MyModel(id=1) == MyModel(id=1)
MyModel(id=1) != MyModel(id=2)
# Primary keys are None
MyModel(id=None) != MyModel(id=None)
# Same instance
instance = MyModel(id=None)
instance == instance
# Proxy model
MyModel(id=1) == MyProxyModel(id=1)
# Multi-table inheritance
MyModel(id=1) != MultitableInherited(id=1)
__hash__()
¶
-
Model.
__hash__
()[исходный код]¶
Метод __hash__()
основан на значении первичного ключа экземпляра. Это эффективно hash(obj.pk)
. Если у экземпляра нет значения первичного ключа, то будет вызвано TypeError
(в противном случае метод __hash__()
будет возвращать разные значения до и после сохранения экземпляра, но изменяя __hash__()
значение экземпляра запрещено в Python.
get_absolute_url()
¶
-
Model.
get_absolute_url
()¶
Определите метод get_absolute_url()
, чтобы сообщить Django, как рассчитать канонический URL для объекта. По мнению вызывающих, этот метод должен возвращать строку, которая может использоваться для ссылки на объект по HTTP.
Например:
def get_absolute_url(self):
return "/people/%i/" % self.id
Хотя этот код является правильным и простым, он может быть не самым переносимым способом написания такого рода метода. Функция reverse()
обычно является наилучшим подходом.
Например:
def get_absolute_url(self):
from django.urls import reverse
return reverse("people-detail", kwargs={"pk": self.pk})
В одном месте Django использует get_absolute_url()
в приложении администратора. Если объект определяет этот метод, страница редактирования объекта будет иметь ссылку «View on site», которая приведет вас непосредственно к общему представлению объекта, как указано в get_absolute_url()
.
Аналогично, пара других частей Django, таких как инфраструктура канала синдикации, используют get_absolute_url()
, когда она определена. Если для каждого экземпляра вашей модели имеет смысл иметь уникальный URL-адрес, вы должны определить get_absolute_url()
.
Предупреждение
Вы должны избегать создания URL из неподтвержденного пользовательского ввода, чтобы уменьшить возможности ссылки или перенаправления:
def get_absolute_url(self):
return "/%s/" % self.name
Если self.name
равно '/example.com'
, это возвращает '//example.com/'
, который, в свою очередь, является действительным URL-адресом схемы, но не ожидаемым '/%2Fexample.com/'
.
Хорошей практикой является использование get_absolute_url()
в шаблонах вместо жесткого кодирования URL-адресов ваших объектов. Например, этот код шаблона плох:
<!-- BAD template code. Avoid! -->
<a href="/people/{{ object.id }}/">{{ object.name }}</a>
Этот шаблон кода намного лучше:
<a href="{{ object.get_absolute_url }}">{{ object.name }}</a>
Логика здесь заключается в том, что если вы изменяете структуру URL-адресов ваших объектов, даже для чего-то простого, например, для исправления орфографической ошибки, вам не нужно отслеживать каждое место, где может быть создан URL-адрес. Укажите его один раз в get_absolute_url()
и пусть весь ваш другой код вызывает только его.
Примечание
Строка, возвращаемая из get_absolute_url()
, должна содержать только символы ASCII (это предусмотрено спецификацией URI, RFC 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
в качестве псевдонима связанной базы данных.