Rendering data from child classes having parent queryset in multi-table inheritance

Hello everyone. I’m playing around with multi-table inheritance to understand if this approach fits my requirements and I have a questions regarding accessing child instances from parent queryset.

Let’s say I have some code:

class Component(models.Model):
    maker = models.CharField()
    model = models.CharField()

class Cpu(Component):
    frequency = models.CharField()

class Motherboard(Component):
    socket = models.CharFIeld()

class ComponentSetup(models.Model):
    component = models.ForeignKey(Component)
    setup = models.ForeignKey(Setup)
    qty = models.PositiveIntegerField()

class Setup(models.Model):
    components = models.ManyToMany(Component, through="ComponentSetup")

class Computer(models.Model):
    type = models.CharField()
    setup = models.ForeignKey(Setup)

So the Component model was made to avoid declaring lot of fields in Setup model (such as Motherboard, Cpu, Memory etc.). So Setup requires queryset of Component instances.

The question:
Once Setup created how can I render in template data for every Component child?
Okay, there might be loop for all components with weird checking every instance or doing the same loop within view and passing context. What is a common approach for such a goal or this models design is not right from beginning ?

Keep in mind that templates don’t care whether variables exist or not. If the issue is simply rendering this data, it’s a lot easier just to try rendering the related class.

For example:
(This is just to give you an idea and is not intended to be complete code.)

{% for component in setup.components.all %}
   {{ component.maker }}
   {{ component.model }}
   {{ component.cpu.frequency }}
   {{ component.motherboard.socket }}
{% endfor %}

If you don’t want the blank space for a component that doesn’t exist, you could wrap these up in an {% if tag.
(Note: You’ll want to ensure your queries in the view are properly using the select_related and prefetch_related functions to minimize the number of queries being executed for this.)

1 Like

So, to extract child (let’s say Cpu instance) fields: maker and model I have to filter() the parent class for exact child I need and, if I understood right, there is only way to check if Cpu in Component queryset is just using if or try to catch the match?

The Cpu model doesn’t have fields maker and model. Those fields are part of the Component model. Those fields exist in every instance of Component.

There is no Cpu in a queryset for Component, there are only instances of Component. Some of those Component may be related to an instance of Cpu, but the presence or absence of a related Cpu has no effect on the instance of Component.

So yes - you can either use an if or a try / catch block to determine whether any specific instance of Component has a related Cpu instance.

@KenWhitesell thank you for helping me to understand some common things.
And the last question, if I may, to cover some gap in my understanding of topic above:
If I go from oposite letting user / customer to create his own Setup where some of the components predefined (as computer won’t start without cpu or motherboard) but some components are optional. How user can pick particular Component’s child using a form if there is relationg with Component instances but not Gpu, for example?

I’m sorry, I’m not following what you’re asking here.

As a general principle, always remember that multi-table inheritance is implemented as two tables joined by a OneToOneField. The most significant difference is that the child model can reference the fields of the parent without specifying the fk field name in the expression. If you keep this in mind, I think it would help you understand what needs to be done.

Also keep in mind that structurally, you could have both a Cpu and a Motherboard related to the same Component. I’m not saying that this makes logical sense in your situation - only that it’s physically possible for this to occur. Again, this is one of those cases where understanding how this is being implemented in the database may add clarity to your thought processes for what you may need to do in your code.

1 Like

Thanks a lot for clearing my doubts, @KenWhitesell!