Переопределенный в Django метод сохранения экземпляров не возвращает фактические данные после super().save()
У меня есть простая Shipment модель. Мне нужно получить доступ к обновленным данным полей экземпляра Shipment после save(). Но когда я пытаюсь подсчитать Product экземпляров, связанных с Shipment экземпляром, я получаю неактуальные данные (одно сохранение позади).
Пример потока:
- Создание новой
Shipmentформы с добавлением одногоProductэкземпляра сChoiceField; - Определение
Shipmentsave()сначала сохраняет экземпляр; - After
save()Я пытаюсь подсчитать только что добавленные товары, при этомself.products.all().count()получает 0 при первомsave(); - После повторного создания нового
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'