7Stuffs
7Stuffs

Reputation: 85

How to get all related objects in relationship model with single queryset?

I want to get all objects from a User model with single queryset, but I have no idea on how to do it.

I got a 2 relationship model to user model, I can get the objects with these code below

User.objects.get(id=1).profile
User.objects.get(id=1).groups

But how can i get all objects of user with single queryset only?

Upvotes: 6

Views: 14915

Answers (2)

Durai
Durai

Reputation: 525

You can access the data of ManyToMany, Foreign field data in queryset with below format double underscore.

columnname.referred.table__reference_column

class DigitalApplicationsAndPlatform(models.Model):
    digital_area = models.ForeignKey(
        MasterDigitalProductsAreas, on_delete=models.CASCADE
    )
    keywords = models.ManyToManyField(
        "MasterKeyword", blank=True, related_name="digital_keyword"
    )

Queryset:

m = models.DigitalApplicationsAndPlatform.objects.filter(id=1).values(
    "digital_product", "digital_area__digital_area", "keywords__keyword"
)

Above queryset will have multiple values of digital_product, digital_area__digital_area, since keywords field has ManyToMany relationship.

Result:

<QuerySet [{'digital_product': '10,000ft Insights',
'digital_area__digital_area': 'Productivity & Collaboration',
'keywords__keyword': '_10000ft Insights_'}, {'digital_product': '10,000ft
Insights', 'digital_area__digital_area': 'Productivity & Collaboration',
'keywords__keyword': '_10K Insights_'}, {'digital_product': '10,000ft
Insights', 'digital_area__digital_area': 'Productivity & Collaboration',
'keywords__keyword': '_10,000ft Insights_'}, {'digital_product': '10,000ft
Insights', 'digital_area__digital_area': 'Productivity & Collaboration',
'keywords__keyword': "_10K' Insights_"}]>

Above query have performance implication. Django hits database everytime you try to access related model data.

m = (
    models.DigitalApplicationsAndPlatform.objects.filter(id=1)
    .select_related("digital_area")
    .prefetch_related("keywords")
    .values("digital_product", "digital_area__digital_area", "keywords__keyword")
)

You have use below hints to tackle it with above queryset.

  • select_related - for Foreign key and OneToOne field.
  • prefetch_related - For ManyToMany and Reverse lookup

Below official document will give some idea about accessing related data.

https://docs.djangoproject.com/en/2.2/topics/db/queries/#lookups-that-span-relationships

Upvotes: 1

dirkgroten
dirkgroten

Reputation: 20702

Use select_related and prefetch_related, as described here:

user = User.objects.select_related('profile').prefetch_related('groups').get(id=1)
user.profile  # does not query the database again
user.groups  # does not query the database again

Note however that since user <-> groups is a m2m relationship, this will hit the database twice in any case. If you're only fetching one specific user, adding the prefetch_related doesn't really make a difference. It does make a difference if you loop through a list of users, since only one query is required to fetch all m2m related groups, instead of one query for each user:

users = User.objects.select_related('profile').prefetch_related('groups')\
     .filter(is_staff=True)
for user in users:  # 2 queries
    print(user.profile)
    for group in user.groups:  # no database query
        print(group.name)

Upvotes: 5

Related Questions