Kurt Peek
Kurt Peek

Reputation: 57761

How to get all the related fields from a query set in Django?

I have two models, Session and SessionType which have a many-to-one relationship. There is also a Family foreign key on Session, like so:

from django.db import models


class SesssionType(models.Model):
    pass


class Session(models.Model):
    session_type = models.ForeignKey('SessionType')
    family = models.ForeignKey('Family')

For a certain instance family of Family, I have several Session objects in the session_set:

ipdb> family.session_set.all()
<QuerySet [<Session: Welcome>, <Session: Breastfeeding Preparation - Timothy Anderson>, <Session: First-Time Parents: The Basics of Birth>, <Session: Initial Postpartum Lactation>, <Session: Sleep Techniques for New Babies>, <Session: Breastfeeding Preparation>, <Session: Newborn Care Basics>, <Session: Easing the Transition Back to Work>, <Session: Preparing for Parenting>, <Session: Decoding Baby Cues>, <Session: Postpartum Doula Support>, <Session: First-Time Parents: Birth Prep Q&A>, <Session: Postpartum Lactation Follow-Up>, <Session: Sleep Training for 4 Months & Beyond>, <Session: Mental Wellness in Pregnancy>, <Session: Infant CPR>, <Session: Prenatal Pelvic Physical Therapy>, <Session: Prenatal Massage>]>

I would like to get a queryset containing the SessionTypes of these Sessions, similar to the following list:

ipdb> [session.session_type for session in family.session_set.all()]
[<SessionType: Welcome>, <SessionType: Breastfeeding Preparation>, <SessionType: First-Time Parents: The Basics of Birth>, <SessionType: Initial Postpartum Lactation>, <SessionType: Sleep Techniques for New Babies>, <SessionType: Breastfeeding Preparation>, <SessionType: Newborn Care Basics>, <SessionType: Easing the Transition Back to Work>, <SessionType: Preparing for Parenting>, <SessionType: Decoding Baby Cues>, <SessionType: Postpartum Doula Support>, <SessionType: First-Time Parents: Birth Prep Q&A>, <SessionType: Postpartum Lactation Follow-Up>, <SessionType: Sleep Training for 4 Months & Beyond>, <SessionType: Mental Wellness in Pregnancy>, <SessionType: Infant CPR>, <SessionType: Prenatal Pelvic Physical Therapy>, <SessionType: Prenatal Massage>]

It seems like the select_related method is meant for this, but calling it doesn't produce the desired result:

ipdb> family.session_set.select_related('session_type')
<QuerySet [<Session: Welcome>, <Session: Breastfeeding Preparation - Timothy Anderson>, <Session: First-Time Parents: The Basics of Birth>, <Session: Initial Postpartum Lactation>, <Session: Sleep Techniques for New Babies>, <Session: Breastfeeding Preparation>, <Session: Newborn Care Basics>, <Session: Easing the Transition Back to Work>, <Session: Preparing for Parenting>, <Session: Decoding Baby Cues>, <Session: Postpartum Doula Support>, <Session: First-Time Parents: Birth Prep Q&A>, <Session: Postpartum Lactation Follow-Up>, <Session: Sleep Training for 4 Months & Beyond>, <Session: Mental Wellness in Pregnancy>, <Session: Infant CPR>, <Session: Prenatal Pelvic Physical Therapy>, <Session: Prenatal Massage>]>

As seen above, the call to select_related() produced a query set with Session objects, and not SessionType objects. How can I get the SessionType objects?

Upvotes: 2

Views: 7595

Answers (3)

allan
allan

Reputation: 343

Do the query to get all the sessions for a family but only ask for the 'session_type' value to be returned rather than all the data for each session.

Once you have only the session_types returned, you can then use distinct() to get that response boiled down to only a list of the unique values.


family.session_set.all().values('session_type').distinct()

Upvotes: 1

vorujack
vorujack

Reputation: 1950

as you say you can use new query set to select all SessionType objects.

but select_related usage is different

according to Django documentation and all I used select_related not change queryset object type. but only select all related objects from database by one query. for example see this query:

for item in family.session_set.select_related('session_type').all():
     print item.session_type

hits database once but when you write this:

for item in family.session_set.all():
     print item.session_type

for every print one database hit occurred and one database hit for base query occurred. its not important for little data but when your data is too large your site went slow without select_related. but be aware of using it. if you use it too much the action is opposite and your site went slow.

see more on https://docs.djangoproject.com/en/2.0/ref/models/querysets/#select-related

Upvotes: 1

Kurt Peek
Kurt Peek

Reputation: 57761

I worked around this problem by filtering all SessionType objects, like so:

ipdb> SessionType.objects.filter(session__family=family).order_by('session__session_number')
<QuerySet [<SessionType: Welcome>, <SessionType: First-Time Parents: The Basics of Birth>, <SessionType: Initial Postpartum Lactation>, <SessionType: Sleep Techniques for New Babies>, <SessionType: Breastfeeding Preparation>, <SessionType: Newborn Care Basics>, <SessionType: Easing the Transition Back to Work>, <SessionType: Preparing for Parenting>, <SessionType: Decoding Baby Cues>, <SessionType: Postpartum Doula Support>, <SessionType: First-Time Parents: Birth Prep Q&A>, <SessionType: Postpartum Lactation Follow-Up>, <SessionType: Sleep Training for 4 Months & Beyond>, <SessionType: Mental Wellness in Pregnancy>, <SessionType: Infant CPR>, <SessionType: Prenatal Pelvic Physical Therapy>, <SessionType: Prenatal Massage>]>

However, I have an inkling that this is less efficient than just getting the corresponding session_type from the Session objects in the family.session_set, so explanations as to why select_related() is not working as expected are still most welcome.

Upvotes: 1

Related Questions