Spec-Zone.ru › Django 2.2

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

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

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

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

Для создания нового экземпляра модели просто проинициализируйте его как любой другой класс 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().

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

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

>>> obj = MyModel.objects.first()
>>> del obj.field
>>> obj.field  # Loads the field from the database
Model.refresh_from_db(using=None, fields=None) [source]

Если вам нужно перезагрузить значения модели из базы данных, вы можете использовать метод 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() [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 gettext_lazy as _

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

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

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

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

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

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

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

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

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

Как вызвать ошибки валидации, относящиеся к конкретным полям, если эти поля отсутствуют в ModelForm

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

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

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

Этот метод похож на clean_fields(), но он проверяет все ограничения уникальности вашей модели вместо отдельных значений полей. Необязательный параметр 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 b2 doesn't have an ID yet.
>>> b2.save()
>>> b2.id     # Returns the ID of your new object.

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

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

Свойство pk

Model.pk

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

Явное указание значений автопервичных ключей

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

>>> b3 = Blog(id=3, name='Cheddar Talk', tagline='Thoughts on cheese.')
>>> b3.id     # Returns 3.
>>> b3.save()
>>> b3.id     # Returns 3.

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

Учитывая приведенный выше пример блога 'Cheddar Talk', этот пример перепишет предыдущую запись в базе данных:

b4 = Blog(id=3, name='Not Cheddar', tagline='Anything but cheese.')
b4.save()  # Overrides the previous blog with ID=3!

См. Как Django определяет UPDATE или INSERT ниже, чтобы понять причину этого.

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

Если вы используете PostgreSQL, последовательность, связанную с первичным ключом, может потребоваться обновить; см. Указание значений автоинкрементируемых первичных ключей вручную.

Что происходит при сохранении?

Когда вы сохраняете объект, Django выполняет следующие шаги:

  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 абстрагирует необходимость использования операторов SQL INSERT или UPDATE. В частности, при вызове 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. Сериализованные копии не должны использоваться в качестве части долгосрочной стратегии архивации.

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

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

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

__str__()

Model.__str__() [source]

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

Например:

from django.db import models

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

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

__eq__()

Model.__eq__() [source]

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

Например:

from django.db import models

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

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

class MultitableInherited(MyModel):
    pass

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

__hash__()

Model.__hash__() [source]

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

get_absolute_url()

Model.get_absolute_url()

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

Например:

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

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

Например:

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

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

END_OF_DOCUMENT_MARKER

Аналогично, несколько других компонентов Django, таких как фреймворк для лент Syndication, используют 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'
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/2.2/ref/models/instances/

Spec-Zone.ru

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