The question title is quite the sentence, but hopefully the code below will clear it up:
class Foo(models.Model):
...
class AbstractParent(models.Model):
foos = models.ManyToManyField(
Foo,
related_name='%(app_label)s_%(class)s_related'
)
def bar(self):
...
class Meta:
abstract = True
class ChildOne(AbstractParent):
...
class ChildTwo(AbstractParent):
...
Lets say that my app's label is 'myapp'.
Basically, the base class of the ChildOne
and ChildTwo
has a M2M to the class Foo
. What I want to do is this: whenever an object of the Foo
class is saved, I want to call the bar()
method of all the objects of ClassOne
and ClassTwo
which has a relation to the Foo
object through the foos
field. To do this, I tried writing a simple signal:
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save, sender=Foo)
def call_bar_for_all_related_objects_to_foo(sender, instance, **kwargs):
# Do the thing
At this point, Im kinda lost. How do I query all the children classes of the AbstractParent
class and call their bar()
methods whenever there is a relation to the instance
in the signal? Ideally, I want to query my database only once, and in one query, I want to get all the objects of ChildOne
and ChildTwo
related to the instance
in the signal. Please note, in my actual models, there are more than two child classes of the AbstractParent
, so an answer that keeps that in mind is appreciated. Thanks for any help.
Well, it doesn't satisfy your single query requirement, but here's a way to at least get the job done with a query per child class:
def call_bar_for_all_related_objects_to_foo(sender, instance, **kwargs):
for field in instance._meta.get_fields():
if not field.related_model:
continue
if not issubclass(field.related_model, AbstractParent):
continue
for related_object in getattr(instance, field.related_name).all():
related_object.bar()
I don't think this can be done in a single query in a general way like this. The only way I know to get whole related django objects out of a single query is via select_related
, which doesn't work with ManyToMany
relationships.
If a single query is important, implementation will probably require more specific details on .bar()
, which would likely need to be refactored into a class method that works on the results of a .values()
call or something.