darkhorse
darkhorse

Reputation: 8722

How to get objects from two different tables that have a relationship to a third table using the related names in Django?

Let me explain. I have 2 tables which are child classes of another abstract table. The abstract table has a relationship to a model called Foo. The related_name is set dynamically. The code looks like this:

class Foo(models.Model):
    ...

class Parent(models.Model):
    foo = models.ForeignKey(
        Foo,
        on_delete=models.CASCADE,
        related_name='%(app_label)s_%(class)s_related'
    )
    ...

    def bar(self):
        print('bar')

    class Meta:
        abstract = True

class ChildOne(Parent):
    ...

class ChildTwo(Parent):
    ...

Therefore, the related names become 'myapp_childone_related', and 'myapp_childtwo_related'.

Now, lets say I want to call the bar() method of all the objects from the ChildOne and ChildTwo model that is related to a Foo object. There is a catch though, I want to it from with a class method of the Foo model. Currently, I'm doing it like this:

 class Foo(models.Model):
     ...

     def call_bar(self):
         references = ('childone', 'childtwo')
         for ref in references:
             children = getattr(self, f'myapp_{ref}_related').all()
             for child in children:
                 child.bar()

This works fine, but honestly feels a bit hack-y, especially when dealing with more than two children classes. Is there a nicer, more Pythonic solution to this problem?

Edit: I decided not to mention previously that I wanted to call the bar() method from within a class method of the Foo model because I thought that it was unnecessary for this question. However, Daneil Roseman's answer suggested making a list of classes, which is a good solution, but it would not work within the class method, as the classes have not yet been defined at that point in the module. So mentioning that in this edit.

Upvotes: 0

Views: 74

Answers (1)

Daniel Roseman
Daniel Roseman

Reputation: 599490

A related_name is only syntactic sugar for performing a query from the related class itself. So you should just do this explicitly:

child_classes = [ChildOne, ChildTwo]
for child_class in child_classes:
    children = child_class.objects.filter(foo=foo)

Upvotes: 1

Related Questions