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

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

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

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

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

классModel ( ** kwargs )

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

Заметка

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

  1. Добавьте метод classmethod в класс модели:

    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() вызове метода модели.

При использовании формы 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. Передайте сигнал перед записью. Сигнал django.db.models.signals.pre_save отправляется, позволяя любой функции, слушающей этот сигнал, предпринять действия.

  2. Подготовка данных. Метод pre_save() каждого поля вызывается для выполнения любого возможного автоматического изменения данных. Например, поля даты / времени переопределяют, pre_save() чтобы реализовать auto_now_add и auto_now .

  3. Подготовка данных для базы данных. Метод get_db_prep_save() каждого поля должен предоставлять свое текущее значение в типе данных, который может быть записан в базу данных.

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

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

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

  5. Выходной сигнал после записи. Сигнал django.db.models.signals.post_save отправляется, позволяя любой функции, слушающей этот сигнал, предпринять действия.

Как Django отличает UPDATE от INSERT

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

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

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

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

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

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

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

Ограничение вставки или обновления

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

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

Использование update_fields принудительного обновления так же, как и force_update .

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

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

>>> product = Product.objects.get(name='Venezuelan Beaver Cheese')
>>> product.number_sold += 1
>>> product.save()

Если number_sold существующее значение в базе данных равно 10, значение 11 будет записано как новое значение в базе данных.

Этот процесс можно упрочить, избегая конфликта конкуренции , и сделать его немного быстрее, выражая обновление относительно существующего значения, а не явно назначая новое значение. Django предоставляет некоторые средства для достижения такого рода относительного обновления. Используя des , предыдущий пример формулируется следующим образом:expressions F expressions F

>>> from django.db.models import F
>>> product = Product.objects.get(name='Venezuelan Beaver Cheese')
>>> product.number_sold = F('number_sold') + 1
>>> product.save()

Для получения дополнительных сведений см. Документацию и их использование в запросах на обновление .expressions F

Указание полей для сохранения

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

product.name = 'Name changed again'
product.save(update_fields=['name'])

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

Невозможно разделить сериализацию "pickle" между разными версиями.

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

Поскольку ошибки совместимости 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 (в противном случае метод __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 (требование спецификации URIRFC 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 ©2020 All rights reserved