Сигналы Django против переопределения метода сохранения

89

У меня проблемы с осознанием этого. Прямо сейчас у меня есть несколько моделей, которые выглядят примерно так:

 def Review(models.Model)
    ...fields...
    overall_score = models.FloatField(blank=True)

def Score(models.Model)
    review = models.ForeignKey(Review)
    question = models.TextField()
    grade = models.IntegerField()

У обзора есть несколько «оценок», total_score - это среднее значение оценок. Когда обзор или оценка сохранены, мне нужно пересчитать среднее значение total_score. Сейчас я использую переопределенный метод сохранения. Есть ли какие-то преимущества в использовании диспетчера сигналов Django?

Imjoevasquez
источник

Ответы:

84

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

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

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

С django-mptt , например, я использовал pre_saveсигнал для управления набором полей, которые описывают древовидную структуру для модели, которая будет создана или обновлена, и pre_deleteсигнал для удаления деталей древовидной структуры для удаляемого объекта и всего его поддерево объектов перед ним, и они удаляются. Благодаря использованию сигналов, пользователи не должны добавлять или изменять saveили deleteметоды на свои модели , чтобы это руководство сделало для них, они просто должны позволить Джанго-mptt знать , какие модели они хотят, чтобы управлять.

Джонни Бьюкенен
источник
Что делать, если обработчик сигнала вызывает исключение? Я полагаю, они не должны вызывать исключения, иначе они не подходят. Я ошибся?
x-
20

Ты спрашивал:

Есть ли какие-то преимущества в использовании диспетчера сигналов Django?

Я нашел это в django docs:

Переопределенные методы модели не вызываются при массовых операциях

Обратите внимание, что метод delete () для объекта не обязательно вызывается при массовом удалении объектов с помощью QuerySet или в результате каскадного удаления. Чтобы обеспечить выполнение настроенной логики удаления, вы можете использовать сигналы pre_delete и / или post_delete.

К сожалению, при массовом создании или обновлении объектов нет обходного пути, поскольку не вызываются функции save (), pre_save и post_save.

От: Переопределение стандартных методов модели

Геттли
источник
3
В представлении списка администраторов Django используется массовое удаление ... был сбит с толку, пока не наткнулся на этот лакомый кусочек.
NBalauro
7
в нем также говорится: «К сожалению, при массовом создании или обновлении объектов нет обходного пути, поскольку не вызываются функции save (), pre_save и post_save». - поэтому я не думаю, что это компромисс между этими методами.
Кори
Это применимо к обоим методам, поэтому ответ таков: «нет, нет никакой пользы от использования сигналов по сравнению с переопределением saveметода»?
Flimm
3

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

Дмитрий Шевченко
источник
2

Это своего рода денормализация. Посмотрите на это красивое решение . Определение поля композиции на месте.

Алексей Кошелев
источник
1

Небольшое дополнение из документации Django о массовом удалении ( .delete()метод для QuerySetобъектов):

Имейте в виду, что это будет, когда это возможно, выполняться исключительно в SQL, и поэтому методы delete () отдельных экземпляров объекта не обязательно будут вызываться во время процесса. Если вы предоставили собственный метод delete () для класса модели и хотите убедиться, что он вызывается, вам нужно будет «вручную» удалить экземпляры этой модели (например, перебирая QuerySet и вызывая delete () для каждый объект индивидуально), а не использовать метод массового удаления () QuerySet.

https://docs.djangoproject.com/en/1.11/topics/db/queries/#deleting-objects

И массовое обновление ( .update()метод по QuerySetобъектам):

Наконец, поймите, что update () выполняет обновление на уровне SQL и, таким образом, не вызывает никаких методов save () в ваших моделях, а также не испускает сигналы pre_save или post_save (которые являются следствием вызова Model.save ( )). Если вы хотите обновить кучу записей для модели, которая имеет собственный метод save (), переберите их и вызовите save ()

https://docs.djangoproject.com/en/2.1/ref/models/querysets/#update

валекс
источник
Разве это не относится к обоим?
Flimm