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

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

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

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

Чтобы создать новый экземпляр модели, создайте его, как любой другой класс Python:

класс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")
    

Настройка загрузки модели

classmethodModel.from_db ( db , field_names , values )

from_db()Метод может быть использован для настройки создания экземпляра модели при загрузке из базы данных.

dbАргумент содержит псевдоним для базы данных , модель загружаются из, field_namesсодержит имена всех загруженных полей, и valuesсодержит загруженные значения для каждого поля field_names. Они field_namesнаходятся в том же порядке, что и values. Если все поля модели присутствуют, то valuesгарантированно находятся в __init__()ожидаемом порядке . То есть экземпляр может быть создан с помощью cls(*values). Если какие-либо поля отложены, они не появятся в field_names. В этом случае присвойте значение django.db.models.DEFERRED каждому из отсутствующих полей.

В дополнение к созданию новой модели, то from_db()метод должен установить addingи dbфлаги нового экземпляра _stateатрибута.

Ниже приведен пример, показывающий, как записывать начальные значения полей, загружаемых из базы данных:

from django.db.models import DEFERRED

@classmethod
def from_db(cls, db, field_names, values):
    # Default implementation of from_db() (subject to change and could
    # be replaced with super()).
    if len(values) != len(cls._meta.concrete_fields):
        values = list(values)
        values.reverse()
        values = [
            values.pop() if f.attname in field_names else DEFERRED
            for f in cls._meta.concrete_fields
        ]
    instance = cls(*values)
    instance._state.adding = False
    instance._state.db = db
    # customization to store the original field values on the instance
    instance._loaded_values = dict(zip(field_names, values))
    return instance

def save(self, *args, **kwargs):
    # Check how the current values differ from ._loaded_values. For example,
    # prevent changing the creator_id of the model. (This example doesn't
    # support cases where 'creator_id' is deferred).
    if not self._state.adding and (
            self.creator_id != self._loaded_values['creator_id']):
        raise ValueError("Updating the value of creator isn't allowed")
    super().save(*args, **kwargs)

В приведенном выше примере показана полная from_db()реализация, чтобы прояснить, как это делается. В этом случае можно было бы использовать super()вызов from_db()метода.

Обновление объектов из базы данных

Если вы удаляете поле из экземпляра модели, при повторном доступе к нему значение из базы данных перезагружается:

>>> obj = MyModel.objects.first()
>>> del obj.field
>>> obj.field  # Loads the field from the database
Model.refresh_from_db( используется = None , fields = None )

Если вам нужно перезагрузить значения модели из базы данных, вы можете использовать этот refresh_from_db()метод. Когда этот метод вызывается без аргументов, происходит следующее:

  1. Все неотложенные поля модели обновляются до значений, которые в настоящее время присутствуют в базе данных.
  2. Все кэшированные отношения удаляются из перезагруженного экземпляра.

Из базы данных перезагружаются только поля модели. Другие значения, зависящие от базы данных, такие как аннотации, не перезагружаются. Также @cached_propertyне очищаются никакие атрибуты.

Перезагрузка происходит из базы данных, из которой был загружен экземпляр, или из базы данных по умолчанию, если экземпляр не был загружен из базы данных. usingАргумент может быть использован , чтобы заставить базу данных , используемую для перезагрузки.

Можно принудительно загрузить набор полей с помощью fields аргумента.

Например, чтобы проверить, что update()вызов привел к ожидаемому обновлению, вы можете написать тест, подобный этому:

def test_update_result(self):
    obj = MyModel.objects.create(val=1)
    MyModel.objects.filter(pk=obj.pk).update(val=F('val') + 1)
    # At this point obj.val is still 1, but the value in the database
    # was updated to 2. The object's updated value needs to be reloaded
    # from the database.
    obj.refresh_from_db()
    self.assertEqual(obj.val, 2)

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

class ExampleModel(models.Model):
    def refresh_from_db(self, using=None, fields=None, **kwargs):
        # fields contains the name of the deferred field to be
        # loaded.
        if fields is not None:
            fields = set(fields)
            deferred_fields = self.get_deferred_fields()
            # If any deferred field is going to be loaded
            if fields.intersection(deferred_fields):
                # then load all of them
                fields = fields.union(deferred_fields)
        super().refresh_from_db(using, fields, **kwargs)
Model.get_deferred_fields()

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

Проверка объектов

Проверка модели состоит из трех этапов:

  1. Проверьте поля модели - Model.clean_fields()
  2. Проверить модель в целом - Model.clean()
  3. Проверить уникальность поля - Model.validate_unique()

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

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

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

Этот метод вызывает Model.clean_fields(), Model.clean()и Model.validate_unique()(если validate_uniqueесть True) в указанном порядке и вызывает, ValidationErrorкоторый имеет message_dictатрибут, содержащий ошибки со всех трех этапов.

Необязательный excludeаргумент можно использовать для предоставления списка имен полей, которые можно исключить из проверки и очистки. ModelFormиспользует этот аргумент, чтобы исключить поля, отсутствующие в вашей форме, из проверки, поскольку любые возникшие ошибки не могут быть исправлены пользователем.

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

from django.core.exceptions import ValidationError
try:
    article.full_clean()
except ValidationError as e:
    # Do something based on the errors contained in e.message_dict.
    # Display them to a user, or handle them programmatically.
    pass

Первый шаг full_clean()- очистка каждого отдельного поля.

Model.clean_fields( exclude = None )

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

Второй full_clean()выполняемый шаг - позвонить Model.clean(). Этот метод следует переопределить, чтобы выполнить пользовательскую проверку вашей модели.

Model.clean()

Этот метод следует использовать для обеспечения проверки пользовательской модели и, при желании, для изменения атрибутов вашей модели. Например, вы можете использовать его для автоматического предоставления значения для поля или для проверки, требующей доступа к более чем одному полю:

import datetime
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.translation import gettext_lazy as _

class Article(models.Model):
    ...
    def clean(self):
        # Don't allow draft entries to have a pub_date.
        if self.status == 'draft' and self.pub_date is not None:
            raise ValidationError(_('Draft entries may not have a publication date.'))
        # Set the pub_date for published items if it hasn't been set already.
        if self.status == 'published' and self.pub_date is None:
            self.pub_date = datetime.date.today()

Обратите внимание, однако, что подобный метод Model.full_clean()модели clean()не вызывается, когда вы вызываете save()метод своей модели .

В приведенном выше примере, ValidationError исключение , сгенерированном Model.clean()был экземпляр со строкой, поэтому он будет сохранен в ключе словаря специальных ошибок, NON_FIELD_ERRORS. Этот ключ используется для ошибок, которые привязаны ко всей модели, а не к конкретному полю:

from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
try:
    article.full_clean()
except ValidationError as e:
    non_field_errors = e.message_dict[NON_FIELD_ERRORS]

Чтобы назначить исключения для определенного поля, создайте экземпляр ValidationErrorсо словарем, где ключи - это имена полей. Мы могли бы обновить предыдущий пример, чтобы присвоить ошибку pub_dateполю:

class Article(models.Model):
    ...
    def clean(self):
        # Don't allow draft entries to have a pub_date.
        if self.status == 'draft' and self.pub_date is not None:
            raise ValidationError({'pub_date': _('Draft entries may not have a publication date.')})
        ...

Если вы обнаружите ошибки в нескольких полях во время Model.clean(), вы также можете передать имена полей сопоставления словаря ошибкам:

raise ValidationError({
    'title': ValidationError(_('Missing title.'), code='required'),
    'pub_date': ValidationError(_('Invalid date.'), code='invalid'),
})

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

Как вызвать ошибки проверки для конкретных полей, если эти поля не отображаются в ModelForm

Вы не можете вызывать ошибки проверки Model.clean()для полей, которые не отображаются в форме модели (форма может ограничивать свои поля с помощью Meta.fieldsили Meta.exclude). Это приведет к возникновению ValueError ошибки, поскольку ошибка проверки не может быть связана с исключенным полем.

Чтобы обойти эту дилемму, вместо этого переопределите, Model.clean_fields()поскольку он получает список полей, исключенных из проверки. Например:

class Article(models.Model):
    ...
    def clean_fields(self, exclude=None):
        super().clean_fields(exclude=exclude)
        if self.status == 'draft' and self.pub_date is not None:
            if exclude and 'status' in exclude:
                raise ValidationError(
                    _('Draft entries may not have a publication date.')
                )
            else:
                raise ValidationError({
                    'status': _(
                        'Set status to draft if there is not a '
                        'publication date.'
                     ),
                })
Model.validate_unique( exclude = None )

Этот метод похож на clean_fields(), но проверяет все ограничения уникальности вашей модели вместо отдельных значений полей. Необязательный excludeаргумент позволяет вам предоставить список имен полей, которые нужно исключить из проверки. Он вызовет ValidationErrorошибку, если какие-либо поля не пройдут проверку.

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

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

Чтобы сохранить объект обратно в базу данных, вызовите save():

Model.save( force_insert = False , force_update = False , using = DEFAULT_DB_ALIAS , update_fields = None )

Если вы хотите настроить поведение при сохранении, вы можете переопределить этот save() метод. Дополнительные сведения см. В разделе « Переопределение предопределенных методов модели» .

В процессе сохранения модели тоже есть свои тонкости; см. разделы ниже.

Автоинкремент первичных ключей

Если модель имеет AutoField- автоматически увеличивающийся первичный ключ - тогда это автоматически увеличивающееся значение будет вычислено и сохранено как атрибут вашего объекта при первом вызове save():

>>> b2 = Blog(name='Cheddar Talk', tagline='Thoughts on cheese.')
>>> b2.id     # Returns None, because b2 doesn't have an ID yet.
>>> b2.save()
>>> b2.id     # Returns the ID of your new object.

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

Для удобства каждая модель имеет AutoFieldимя idпо умолчанию, если вы явно не указали primary_key=Trueполе в своей модели. См. Документацию для AutoField получения более подробной информации.

pkСвойство

Model.pk

Независимо от того, определяете ли вы поле первичного ключа самостоятельно или позволяете Django предоставить его для вас, каждая модель будет иметь свойство с именем pk. Он ведет себя как обычный атрибут модели, но на самом деле является псевдонимом для любого атрибута, который является полем первичного ключа для модели. Вы можете прочитать и установить это значение, как и любой другой атрибут, и оно обновит правильное поле в модели.

Явное указание значений автоматического первичного ключа

Если у модели есть, AutoFieldно вы хотите явно определить идентификатор нового объекта при сохранении, определите его явно перед сохранением, а не полагайтесь на автоматическое присвоение идентификатора:

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

  4. Вставьте данные в базу данных. Предварительно обработанные подготовленные данные объединяются в оператор SQL для вставки в базу данных.

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

Как Django знает, что нужно ОБНОВИТЬ против ВСТАВКИ

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

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

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

Единственная проблема здесь заключается в том, что вы должны быть осторожны и не указывать значение первичного ключа явно при сохранении новых объектов, если вы не можете гарантировать, что значение первичного ключа не используется. Подробнее об этом нюансе см. В разделах «Явное указание значений автоматического первичного ключа» выше и « Принудительное выполнение INSERT или UPDATE» ниже.

В Django 1.5 и ранее Django выполнял операцию, SELECTкогда был установлен атрибут первичного ключа. Если SELECTстрока нашла, то Django выполнил UPDATE, в противном случае - INSERT. Старый алгоритм приводит к еще одному запросу по UPDATEделу. В некоторых редких случаях база данных не сообщает, что строка была обновлена, даже если база данных содержит строку для значения первичного ключа объекта. Примером может служить триггер PostgreSQL, который возвращает . В таких случаях можно вернуться к старому алгоритму, установив для параметра значение .ON UPDATENULLselect_on_saveTrue

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

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

Эти параметры могут понадобиться очень редко. 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 expressionsF 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Аргумент может быть любой Iterable , содержащие строки. Пустая update_fieldsитерация пропустит сохранение. Значение Noneобновит все поля.

Указание update_fieldsприведет к обновлению.

При сохранении модели, полученной с помощью отложенной загрузки модели ( only()или defer()), обновляются только поля, загруженные из БД. Фактически update_fieldsв этом случае есть автомат . Если вы назначите или измените какое-либо значение отложенного поля, это поле будет добавлено к обновленным полям.

Удаление объектов

Model.delete( используется = DEFAULT_DB_ALIAS , keep_parents = False )

Выдает SQL DELETEдля объекта. При этом удаляется только объект в базе данных; экземпляр Python по-прежнему будет существовать, и в его полях по-прежнему будут храниться данные. Этот метод возвращает количество удаленных объектов и словарь с количеством удалений для каждого типа объекта.

Дополнительные сведения, в том числе о массовом удалении объектов , см. В разделе Удаление объектов .

Если вы хотите настроить поведение при удалении, вы можете переопределить delete() метод. Дополнительные сведения см. В разделе « Переопределение предопределенных методов модели» .

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

Травление объектов

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

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

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

Поскольку ошибки совместимости pickle бывает трудно диагностировать, например, незаметно поврежденные объекты, возникает RuntimeWarningошибка, когда вы пытаетесь распаковать модель в версии Django, которая отличается от той, в которой она была обработана.

Другие методы экземпляра модели

Некоторые методы объекта имеют особые цели.

__str__()

Model.__str__()

__str__()Метод вызывается всякий раз , когда вы звоните str()на объект. Django использует str(obj)во многих местах. В частности, для отображения объекта на сайте администратора Django и в качестве значения, вставляемого в шаблон, когда он отображает объект. Таким образом, вы всегда должны возвращать из __str__()метода красивое, удобочитаемое представление модели .

Например:

from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)

    def __str__(self):
        return '%s %s' % (self.first_name, self.last_name)

__eq__()

Model.__eq__()

Метод равенства определяется таким образом, что экземпляры с одинаковым значением первичного ключа и одним и тем же конкретным классом считаются равными, за исключением того, что экземпляры со значением первичного ключа Noneне равны ничему, кроме самих себя. Для прокси-моделей конкретный класс определяется как первый не-прокси-родитель модели; для всех остальных моделей это просто класс модели.

Например:

from django.db import models

class MyModel(models.Model):
    id = models.AutoField(primary_key=True)

class MyProxyModel(MyModel):
    class Meta:
        proxy = True

class MultitableInherited(MyModel):
    pass

# Primary keys compared
MyModel(id=1) == MyModel(id=1)
MyModel(id=1) != MyModel(id=2)
# Primary keys are None
MyModel(id=None) != MyModel(id=None)
# Same instance
instance = MyModel(id=None)
instance == instance
# Proxy model
MyModel(id=1) == MyProxyModel(id=1)
# Multi-table inheritance
MyModel(id=1) != MultitableInherited(id=1)

__hash__()

Model.__hash__()

__hash__()Метод основан на значении первичного ключа экземпляра. Это эффективно hash(obj.pk). Если у экземпляра нет значения первичного ключа, тогда TypeErrorбудет поднято a (в противном случае __hash__() метод будет возвращать разные значения до и после сохранения экземпляра, но изменение __hash__()значения экземпляра запрещено в Python.

get_absolute_url()

Model.get_absolute_url()

Определите get_absolute_url()метод, чтобы сообщить Django, как вычислять канонический URL-адрес для объекта. Для вызывающих абонентов этот метод должен возвращать строку, которую можно использовать для ссылки на объект через HTTP.

Например:

def get_absolute_url(self):
    return "/people/%i/" % self.id

Хотя этот код правильный и простой, возможно, это не самый переносимый способ написать такой метод. reverse()Функция, как правило , самый лучший подход.

Например:

def get_absolute_url(self):
    from django.urls import reverse
    return reverse('people.views.details', args=[str(self.id)])

Одно место, которое использует Django, get_absolute_url()- это приложение администратора. Если объект определяет этот метод, на странице редактирования объекта будет ссылка «Просмотр на сайте», которая переместит вас прямо к общедоступному представлению объекта, как указано в get_absolute_url().

Точно так же пара других частей Django, таких как фреймворк синдикации , используются, get_absolute_url()когда он определен. Если для экземпляров вашей модели имеет смысл иметь уникальный URL-адрес, вы должны определить get_absolute_url().

Предупреждение

Вам следует избегать создания URL-адреса из непроверенного пользовательского ввода, чтобы уменьшить вероятность отравления ссылки или перенаправления:

def get_absolute_url(self):
    return '/%s/' % self.name

Если self.nameесть '/example.com'это возвращается , '//example.com/' который, в свою очередь, является действительной схемой относительный URL , но не ожидается '/%2Fexample.com/'.

Рекомендуется использовать get_absolute_url()в шаблонах вместо жесткого кодирования URL-адресов ваших объектов. Например, этот код шаблона плохой:

<!-- BAD template code. Avoid! -->
<a href="/people/{{ object.id }}/">{{ object.name }}</a>

Этот код шаблона намного лучше:

<a href="{{ object.get_absolute_url }}">{{ object.name }}</a>

Логика здесь в том, что если вы измените структуру URL-адресов своих объектов, даже для чего-то небольшого, например исправления орфографической ошибки, вам не захочется отслеживать каждое место, где может быть создан URL-адрес. Укажите его один раз, get_absolute_url()и пусть весь ваш другой код будет вызывать это одно место.

Примечание

Строка, из которой вы возвращаетесь, get_absolute_url() должна содержать только символы ASCII (требуется спецификацией URI,RFC 2396 # section-2 ) и при необходимости закодировать URL-адрес.

Вызов кода и шаблонов get_absolute_url()должен иметь возможность напрямую использовать результат без какой-либо дополнительной обработки. Вы можете использовать эту django.utils.encoding.iri_to_uri()функцию, чтобы помочь с этим, если вы используете строки, содержащие символы вне диапазона ASCII.

Дополнительные методы экземпляра

В дополнение к save(), delete(), объектная модель может иметь некоторые из следующих методов:

Model.get_FOO_display()

Для каждого установленного поля choicesу объекта будет get_FOO_display()метод, где FOO- имя поля. Этот метод возвращает «удобочитаемое» значение поля.

Например:

from django.db import models

class Person(models.Model):
    SHIRT_SIZES = (
        ('S', 'Small'),
        ('M', 'Medium'),
        ('L', 'Large'),
    )
    name = models.CharField(max_length=60)
    shirt_size = models.CharField(max_length=2, choices=SHIRT_SIZES)
>>> p = Person(name="Fred Flintstone", shirt_size="L")
>>> p.save()
>>> p.shirt_size
'L'
>>> p.get_shirt_size_display()
'Large'
Изменено в Django 3.1:

Добавлена поддержка ArrayFieldи RangeField.

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установить на псевдоним связанной базы данных.

Copyright ©2021 All rights reserved