Spec-Zone.ru › Django 1.11

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

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

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

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

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

class Model(**kwargs) [source]

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

Примечание

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

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

    from django.db import models
    
    class Book(models.Model):
        title = models.CharField(max_length=100)
    
        @classmethod
        def create(cls, title):
            book = cls(title=title)
            # do something with the book
            return book
    
    book = Book.create("Pride and Prejudice")
    
  2. Добавьте метод в пользовательский менеджер (обычно предпочтительнее):

    class BookManager(models.Manager):
        def create_book(self, title):
            book = self.create(title=title)
            # do something with the book
            return book
    
    class Book(models.Model):
        title = models.CharField(max_length=100)
    
        objects = BookManager()
    
    book = Book.objects.create_book("Pride and Prejudice")
    

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

classmethod Model.from_db(db, field_names, values) [source]

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

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

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

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

from django.db.models import DEFERRED

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

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

В более ранних версиях вы могли проверить, загружены ли все поля, обратившись к cls._deferred. Этот атрибут удален, и django.db.models.DEFERRED является новым.

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

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

>>> obj = MyModel.objects.first()
>>> del obj.field
>>> obj.field  # Loads the field from the database
Изменено в Django 1.10:

В более ранних версиях доступ к удаленному полю вызывал AttributeError вместо перезагрузки.

Model.refresh_from_db(using=None, fields=None) [source]

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

  1. Все поля модели, которые не отложены, обновляются до значений, которые в данный момент присутствуют в базе данных.
  2. Предыдущие загруженные связанные экземпляры, для которых значение отношения больше недействительно, удаляются из перезагруженного экземпляра. Например, если у вас есть внешний ключ от перезагруженного экземпляра к другой модели с именем Author, а obj.author_id != obj.author.id, то obj.author будет удалено, и при следующем доступе будет перезагружено со значением obj.author_id.

Из базы данных перезагружаются только поля модели. Другие зависящие от базы данных значения, такие как аннотации, не перезагружаются. Любые атрибуты @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(ExampleModel, self).refresh_from_db(using, fields, **kwargs)
Model.get_deferred_fields() [source]

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

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

Существует три шага, вовлеченных в проверку модели:

  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) [source]

Этот метод вызывает 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) [source]

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

Второй этап full_clean() — вызов метода Model.clean(). Этот метод следует переопределять для выполнения пользовательской проверки вашей модели.

Model.clean() [source]

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

import datetime
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.translation import ugettext_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 ValidationError, NON_FIELD_ERRORS
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(Article, self).clean_fields(exclude=exclude)
        if self.status == 'draft' and self.pub_date is not None:
            if exclude and 'status' in exclude:
                raise ValidationError(
                    _('Draft entries may not have a publication date.')
                )
            else:
                raise ValidationError({
                    'status': _(
                        'Set status to draft if there is not a '
                        'publication date.'
                     ),
                })
Model.validate_unique(exclude=None) [source]

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

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

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

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

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

Если вам нужно настроить поведение сохранения, вы можете переопределить этот save() метод. Более подробную информацию см. в разделе Переопределение предопределённых методов модели.

Процесс сохранения модели также имеет некоторые нюансы; см. разделы ниже.

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

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

>>> b2 = Blog(name='Cheddar Talk', tagline='Thoughts on cheese.')
>>> b2.id     # Returns None, because b 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 предположит, что вы изменяете существующую запись, а не создаёте новую.

В приведённом выше примере с блогом это привело бы к переопределению предыдущей записи в базе данных:

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

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

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

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

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

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

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

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

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

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

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

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

Использование update_fields аналогичным образом принудительно выполняет обновление force_update.

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

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

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

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

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

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

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

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

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

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

Аргумент update_fields может быть любым итерируемым объектом, содержащим строки. Пустой update_fields итерируемый объект пропустит сохранение. Значение None выполнит обновление всех полей.

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

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

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

Model.delete(using=DEFAULT_DB_ALIAS, keep_parents=False) [source]

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

Для получения дополнительных сведений, включая удаление объектов большими группами, см. Удаление объектов.

Если вы хотите настроить поведение удаления, вы можете переопределить метод delete(). См. Переопределение предопределённых методов модели для получения дополнительных сведений.

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

Сериализация объектов

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

Нельзя использовать сериализованные копии между версиями

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

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

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

Некоторые методы объекта имеют специальное назначение.

__str__()

Model.__str__() [source]

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

Например:

from django.db import models
from django.utils.encoding import python_2_unicode_compatible

@python_2_unicode_compatible  # only if you need to support Python 2
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)

Если вы хотите обеспечить совместимость с Python 2, вы можете украсить класс своей модели с помощью python_2_unicode_compatible(), как показано выше.

__eq__()

Model.__eq__() [source]

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

Например:

from django.db import models

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

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

class MultitableInherited(MyModel):
    pass

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

__hash__()

Model.__hash__() [source]

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

get_absolute_url()

Model.get_absolute_url()

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

Например:

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

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

Например:

def get_absolute_url(self):
    from django.urls import reverse
    return reverse('people.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) и быть закодированной в URL, если это необходимо.

Код и шаблоны, вызывающие get_absolute_url() , должны быть способны использовать результат напрямую без дальнейшей обработки. Вы можете использовать функцию django.utils.encoding.iri_to_uri() , чтобы помочь в этом, если вы используете строковые значения Unicode, содержащие символы за пределами диапазона 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 в соответствующих случаях.

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

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

Другие атрибуты

DoesNotExist

exception Model.DoesNotExist

Это исключение генерируется ORM в нескольких местах, например, QuerySet.get() при отсутствии объекта для заданных параметров запроса.

Django предоставляет исключение DoesNotExist в качестве атрибута каждого класса модели для идентификации класса объекта, который не может быть найден, и позволяет вам перехватывать конкретный класс модели с try/except. Исключение является подклассом django.core.exceptions.ObjectDoesNotExist.

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/1.11/ref/models/instances/

Spec-Zone.ru

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