How do I join related querysets before passing to a template?

I have three models. One model is used specifically for storing primary keys representing physical objects. Two other models describe attributes of particular characteristics of each physical object (represented by the first model’s primary keys). Each of the two other models include foreign keys pointing to the first model, as follows:

from django.db import models

class UID(models.Model):
    description = models.TextField(blank=True, null=True)

class Char1(models.Model):
    uid = models.ForeignKey(UID, to_field='id', on_delete=models.CASCADE, related_name='char1')
    attr1 = TextField(blank=True, null=True)
    attr2 = TextField(blank=True, null=True)

class Char2(models.Model):
    uid = models.ForeignKey(UID, to_field='id', on_delete=models.CASCADE, related_name='char2')
    attr1 = TextField(blank=True, null=True)
    attr2 = TextField(blank=True, null=True)

I need to join querysets called from each model and render it as a list in a template. My view and template is as follows:

from django.shortcuts import render
from .models import UID, Char1, Char2

def joined_list(request):
    uid = UID.objects.all()
    char1 = Char1.objects.all()
    char2 = Char2.objects.all()
    join = uid + char1 + char3 ### 
    return(render(request, 'links/joined_list.html', {'join':, join}))

{% for i in join %}
{{ }}
{{ i.Char1.attr1 }}
{{ i.Char2.attr2 }}
{% endfor %}

Clearly the join object constructed in the view can’t work, and is what I’m trying to solve here. For clarity, if I was to do this in an SQL-like manner it would look similar to the following:

'SELECT UID.*,Char1.*,Char2.* FROM UID INNER JOIN Char1 ON ( = Char1.uid) INNER JOIN Char2 ( = Char2.uid);'

If I passed the results of the above SQL to a template then it would be a simple matter to render a list in the simple for loop as shown above.

I am almost certain that I need to utilise ‘select_related’ (or ‘preselect_related’) but to do that I think I’d need to have the foreign keys located in the UID model. I need to avoid that because sometimes there is no data in the other two models (those characteristics don’t exist) or there may be multiple instances of those characteristics (a physical object may have two colours, for example).

Am I trying to do things backwards or is there a sensible solution for this.

Thanks and all the best.

You need select_related here, it will do joins for you. Example:

def joined_list(request):
    join = UID.objects.all().select_related('char1', 'char2')
    return(render(request, 'links/joined_list.html', {'join':, join}))