Related Field from Many-to-Many Model

Hi,

Is it possible within a template to access the related field on a model that is not directly linked via fk or many-2-many?

I know I can do this using all to get the related on a linked model, but is it possible to reach across from the intermediate model?

I have 3 models.

class Project(models.Model):

    name = models.CharField(max_length=100, null=False)
    founders = models.ManyToManyField(Founder, blank=True)

    def __str__(self):
        return str(self.name)

class Usergrowth(models.Model):
    project = models.ForeignKey(Project, on_delete=models.CASCADE)
    capture_date = models.DateField(null=False)
    user_count = models.IntegerField(null=False)

    def __str__(self):
        return str(self.project)

class Founder(models.Model):
    name = models.CharField(max_length=100, blank=False)
    score = models.SmallIntegerField(null=True, blank=True)
...

I’m using a really basic function founders = Founder.objects.all().order_by('score').reverse() but within this template, I am trying to get the project for a founder. The founders model holds lots more data that I am trying to present in a table.

I’ve tried {% for project in founder.founders.all %}{{ project.name }}{% endfor %}

Do I need to many-to-many to project from founder or is there a way to do it as it is?

Thanks

Tom

For clarity, are you asking that, given a Founder, you want all the Project it is related to?

Yeah. - is that possible in that view, Ken?

Review the docs and examples at Many-to-many relationships | Django documentation | Django

You may also want to review Related objects reference | Django documentation | Django

Edit: One more link for review: Linked linked to Profile model

Ah I forgot about through

So i think i need to add projects = models.ManyToManyField('Project', blank=True, through='UserGrowth') to my founders model?

And then modify the view to be:
founders = Founder.objects_set.all().order_by('score').reverse()

But this throws

founders.Usergrowth: (fields.E336) The model is used as an intermediate model by 'founders.Founder.projects', but it does not have a foreign key to 'Founder' or 'Project'.

But it doesn have a fk to Project?

class Usergrowth(models.Model):
    project = models.ForeignKey(Project, on_delete=models.CASCADE)
...

Forget about all the excess requirements for your view at the moment.

Assume your models are exactly as they are in your original post. Nothing needs to be added or changed with those models.

If I have an instance of Founder named founder, how can I access all of the instances of Project related to founder?

This is an exact parallel to the relationship between Publication and Article in the examples in the first link. Given a Publication named publication, how do they show how to access all Article related to that publication?

I don’t know - I find the docs confusing.

I’m assuming it would be something like:
founder = founder.objects.all()
founder.project_set.all()

But founder isn’t linked to Project, other than through Usergrowth?

This would be correct:

(Again, the assumption given before is that founder is an instance of Founder, not a queryset, which is the result of Founder.objects.all().)

This is incorrect. Every ForeignKey relating “A” to “B” results in the automatic creation of a related object manager relating “B” to “A”.

You’ve actually used this type of relationship before - that’s why I provided that third link above.

Right, so it would be founder = founder.project_set.all() which would then enable me to pass this as context to my template.

The previous time I did this, was using through but I don’t need to do that this time. Why would that be?

This depends upon what you want to send to the template - but in any event, I would not use founder as the expression on the right side of the expression because the result of founder.project_set.all() is not an object of type Founder, it’s a queryset of type Project.

The only time you need to use through is when you have additional data to be added to the join table between the two ends of the relationship.

Because I want to return all of the founder data related to the project I am using founder.objects.all() but this is returning a queryset rather than an object so I can’t access the relations.

So am I right in thinking that I need to loop through each object in project to retrieve related founder data and store this in a dict

What is your ultimate objective for this? Or, to ask this a different way, what output are you trying to generate? (A sample would be most helpful here.)

I’m looking to show all of the data on founder, along with the project name.

Founder Name | Project           | Score | ...
Mr Smith     | Project 1         | 10    | ...
Mr Jones     | Project x         | 2     |
...

So, you’re showing a page for just one Founder? And you want all the projects associated with that one Founder?

Sorry, I wasn’t clear in what I was asking. I’ve edited my post, but the plan is to have a table with every founder on a single page

And since a Founder can be a Founder of multiple projects, are you looking for something more like this?

Founder Name | Project           | Score | ...
Mr Smith     | Project 1         | 10    | ...
Mr Smith     | Project 2         | 17    | ...
Mr Smith     | Project 3         | 23    | ...
Mr Jones     | Project 4         | 2     |
Mr Jones     | Project 5         | 4     |
Mr Jones     | Project 5         | 4     |
Mr Doe       | Project 2         | 17     |

...

Yep :slight_smile: That’s exactly what I am trying to achieve.

I will make sure I’m clearer in my ask, I’ve made this mistake before.

Cool, now I can address this:

No, this isn’t necessary. You can create nested loops in your templates. Iterate over your founders queryset in the outer loop, and iterate over the project_set for a founder in your inner loop. Then you would render each line of your table in the inner loop.

(Note, you may also want to look at the prefetch_related function. It’s not necessary but it is a performance-enhancement tool.)

Now I am really confused. Sorry, Ken.

I can’t get all of the data from my founders model into a queryset for me to loop through when i am trying to get the relations.

When I use founder.project_set.all() this returns an object rather than a queryset. So how do I get a queryset with the related fields so that I can loop within the template?

Ok, one step at a time.

First the outer loop - you’re trying to iterate over all founders, right? What does that query look like? (Ignore your requirement for the related projects at the moment.)

And so what does your loop in your template look like?