Переопределенный в Django метод сохранения экземпляров не возвращает фактические данные после super().save()
У меня есть простая Shipment
модель. Мне нужно получить доступ к обновленным данным полей экземпляра Shipment
после save()
. Но когда я пытаюсь подсчитать Product
экземпляров, связанных с Shipment
экземпляром, я получаю неактуальные данные (одно сохранение позади).
Пример потока:
- Создание новой
Shipment
формы с добавлением одногоProduct
экземпляра сChoiceField
; - Определение
Shipment
save()
сначала сохраняет экземпляр; - 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
, таким образом, делает программу менее надежной. Я бы реализовал некоторую логику в функции, и пусть представления, изменяющие Product
s или Shipment
, вызывают эту логику для фиксации статуса, или, возможно, лучше: определять статус динамически в @property
или аннотации.
Действительно, например:
class Shipment(models.Model):
# …
@property
def status(self):
if self.products.count() > 5:
return 'too heavy'
else:
return 'ready to ship'