Переопределенный в Django метод сохранения экземпляров не возвращает фактические данные после super().save()

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

Пример потока:

  1. Создание новой Shipment формы с добавлением одного Product экземпляра с ChoiceField;
  2. Определение Shipment save() сначала сохраняет экземпляр;
  3. After save() Я пытаюсь подсчитать только что добавленные товары, при этом self.products.all().count() получает 0 при первом save();
  4. После повторного создания нового Shipment экземпляра и повторного добавления одного Product экземпляра self.products.all().count() возвращает 1. Я знаю о проблеме m2m, когда новый экземпляр m2m добавляется после выполнения save(), но в моем случае FK, похоже, не имеет такой проблемы.

(упрощенно)

class Product(models.Model):
    shipments = models.ForeignKey(Shipment, related_name="products")


class Shipment(models.Model):
    order = models.ForeignKey(Order, related_name="shipments")

    def save(self, *args, **kwargs):
        super(Shipment, self).save(*args, **kwargs)
        count = self.products.all().count() # <-- Returns 0 even after instance saved with including FK model
    

Конечная цель - определить Product количество отгруженных товаров и в зависимости от результата изменить статус Order (модель, связанная с FK).

Я знаю о проблеме m2m, когда новый экземпляр m2m добавляется после выполнения save(), но в моем случае FK предполагает, что такой проблемы не будет.

По сути, это та же самая проблема. Администратор или (Model)Form будет сначала сохранять Shipment и потом сохранять Product, он не может сделать это в обратном порядке, поскольку ему нужен первичный ключ (или какое-то другое поле, на которое ссылается ForeignKey). Поэтому он может не создать Product первым, поскольку он ссылается на Shipment, которое должно быть создано первым. Строго говоря, логика обновления может идти в обратном порядке, но это, вероятно, только усложнит ситуацию, если поток обновления будет отличаться от потока создания.

That being said, typically it is better not store aggregates in the model: determine aggregates when needed: storing aggregates in the model makes updating and keeping data in sync harder. You can use .annotate(…) [Django-doc] to generate counts, sums, etc. per object when needed. So I don't think you should determine the number of products in the Shipment.

Более того, можно динамически добавлять, удалять или связывать Product с (другим) Shipment. Таким образом, без вызова .save() из Shipment количество Product может измениться. Хранение числа Product в явном виде в поле в Shipment, таким образом, делает программу менее надежной. Я бы реализовал некоторую логику в функции, и пусть представления, изменяющие Products или Shipment, вызывают эту логику для фиксации статуса, или, возможно, лучше: определять статус динамически в @property или аннотации.

Действительно, например:

class Shipment(models.Model):
    # …

    @property
    def status(self):
        if self.products.count() > 5:
            return 'too heavy'
        else:
            return 'ready to ship'
Вернуться на верх