Reputation: 191
If I have a queryset qs1 like this:
<QuerySet [{u'name': u'John', u'birthdate': u'1980-01-01'},
{u'name': u'Larry', u'birthdate': u'1976-12-28'},
.....']}
I need to use all values associated with key 'name' from qs1 to query another model and get qs2 like this:
<QuerySet [{u'student_name': u'John', u'grade': u'A'},
{u'student_name': u'Larry', u'grade': u'B'},
.....']}
After this, I have to combine qs1 and qs2 so the final_qs like this:
[{u'name': u'John',u'birthdate': u'1980-01-01', u'grade': u'A'},
{u'student_name': u'Larry', u'birthdate': u'1976-12-28', u'grade': u'B'},
.....']}
How would I achieve this? I have code like this:
qs1 = Person.objects.values('name', 'birthdate')
for t in qs1:
qs2 = Grades.objects.filter(student_name=t['name'])
.values('student_name', 'grade')
My qs1 looks OK. However, my qs2 becomes this:
<QuerySet [{u'student_name': u'John', u'grade': u'A'}]>
<QuerySet [{u'student_name': u'Larry', u'grade': u'B'}]>
Because of qs2, I am not able use zip(qs1, qs2) to construct final_qs the way I want.
Upvotes: 0
Views: 283
Reputation: 4682
I assume that your Grade model contains the ForeignKey(Person)
which means that there is a reverse relation created. Which means that you can "follow the relationship backwards" and all sorts of other django magic.
So given you have a queryset qs1
of Person
s:
>>> qs1.values('student_name', 'birthdate', 'grade_set__grade')
The aforementioned magic can be observed by this mysterious 'grade_set__grade'
.
Django has actually added another field to you Person
model: .grade_set
. This would be all the grades that have the belong to that person instance. We can then access all those grades via djangos double underscore notation that we use in filters.
You can quickly try that out by doing User.objects.last().grade_set
Bonus
Don't like the term 'grade_set', prefer something else? You can change this in the Grade model.
class Grade(models.Model):
# some fields
ForeignKey(Person, related_name='all_their_grades')
# other fields
You can now do User.objects.last().all_their_grades
to do the same as before. Please ntoe that once you change it, the .grade_set
is no longer available.
Upvotes: 0
Reputation: 1589
I would aggregate all qs1
names to a list:
names = [t['name'] for t in qs1]
And then execute the following query:
qs2 = Grades.objects.filter(student_name__in=names)
.values('student_name', 'grade')
The latter would select only the rows where student_name
is in the names
from the qs1
and should return a single QuerySet
with all matching rows.
Upvotes: 1