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?
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 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?