I have an Animal
model and a Herd
model that looks like this:
from django_lifecycle.hooks import AFTER_CREATE
class Animal(models.Model):
parent = OneToOneField("self", related_name="child")
age = IntegerField()
class Herd(models.Model):
animal = OneToOneField(Animal)
total_age = IntegerField()
@hook(AFTER_CREATE)
def create_animal_child(self):
if self.animal.child.exists():
Herd.objects.create(parent=self, animal=self.animal.child)
def save_total_age(self):
total_age = self.animal.age
position = self.animal
while position.child.exists():
total_age = position.child.age
position = position.child
The idea being that you create your Animal
s. Then you create your Herd
for the topmost animal you want. The Herd's AFTER_CREATE
will then create a "chain" of all the Herd
objects for the Animal
's children, the children's children, and so on.
E.g.
a1 = Animal.objects.create(age=10)
a2 = Animal.objects.create(parent=a1, age=7)
a3 = Animal.objects.create(parent=a2, age=3)
h1 = Herd.objects.create(animal=a1)
# Two Herd objects with an "animal" field pointing to a2 and a3 respectively are automatically created
h1.save_total_age() # h1.total_age = 20 # 10 7 3
Which is all fine.
My problem is for my front-end, how can I tell when all the relevant Animal
AFTER_CREATE
hooks have finished running so I know to call my calculate_total_age
method?
So say I have the following REST API endpoints:
example.com/api/animals/<pk>
example.com/api/herds/<pk>
example.com/api/herds/<pk>/save_total_age
If I do a POST to example.com/api/herds/<pk>
to create a Herd
, I call save_total_age()
as soon as that "parent" Herd
is created - and not necessarily after all the "children" Herd
s have been created via the AFTER_CREATE
hook.
axios.post(
"example.com/api/herds/",
{animal_id: 1}
).then((response) => {
axios.post(
`example.com/api/herds/${response.data.pk}/save_total_age`,
{},
)
});
How can I set my backend signals and/or frontend async/await so that save_total_age()
only runs after my AFTER_CREATE
chain is complete?
Edit: My best solution right now is to add some condition to save_word_count()
that makes sure the Herd
chain has the same # of objects as the Animal
chain. If so, run the method. If not, return a bad request and retry the POST.
CodePudding user response:
Signals (which are called by those hooks) run synchronously, not asynchronously. So when you call create()
for your first heard, it will always run the AFTER_CREATE
hook and create the 2nd Heard object, before it returns and let you run the save_total_age()
method.
In other words this should work just fine as it is.