[Django]-"_set" in a queryset object in Django

71👍

What you are seeing is a reverse related object lookup.

In your example:

class Blog(models.Model):
    pass

class Entry(..):
    blog = Blog(..)

Now, given object e of type Entry, you would do e.blog to access the related object Blog – which is a forward relation.
The _set is a reverse lookup class variable django puts in for you.

So, given object b – you would do:

entries = b.entry_set.all()

The reason the reverse is a queryset is, ForeignKey is 1-to-many relationship. Hence, the reverse is a queryset.

The _set object is made available when related_name is not specified.

44👍

Briefly speaking:

Suppose you have a model Car and a model Wheel. Wheel has a foreign key relationship with Car as follows:

class Car(models.Model):
    pass

class Wheel(models.Model):
    car = models.ForeignKey(Car, on_delete=models.CASCADE) # on_delete parameter is mandatory in Django 2.0

Let’s say w is an instance of Wheel, and c is an instance of Car:

>>> w.car # returns the related Car object to w
>>> c.wheel_set.all() # returns all Wheel objects related to c

Detailed explanation

Using the models defined above, a Wheel object w can get its associated Car object by accessing the car attribute: w.car.

If a model has a ForeignKey, instances of that model will have access to the related foreign object via a simple attribute of the model.

According to the official Django documentation:

Django also creates API accessors for the “other” side of the relationship – the link from the related model to the model that defines the relationship.

In this case, a Car object c has access to a list of all related Wheel objects via the wheel_set attribute: c.wheel_set.all().

If a model has a ForeignKey, instances of the foreign-key model will have access to a Manager that returns all instances of the first model. By default, this Manager is named FOO_set, where FOO is the source model name, lowercased. This Manager returns QuerySets, which can be filtered and manipulated.

1👍

_set can access the child model which has the foreign key of the parent model.

For example, there is the child model Product which has the foreign key of the parent model Category as shown below:

"models.py"

from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=20)

class Product(models.Model):
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    name = models.CharField(max_length=50)
    price = models.DecimalField(decimal_places=2, max_digits=5)

Then, you can access the child model Product from the parent model Category with _set as shown below:

category_obj = Category.objects.all()[0]
product_obj = category_obj.product_set.all()[0]
                                # ↑ Here
print(product_obj.id, product_obj.name, product_obj.price)

Output:

1 Apple 10.00

But, you cannot access the parent model Category from the child model Product with _set as shown below:

product_obj = Product.objects.all()[0]
category_obj = product_obj.category_set.all()[0]
                                 # ↑ Cannot access "Category" with "_set"
print(category_obj.id, category_obj.name)

Then, the error below occurs:

AttributeError: ‘Product’ object has no attribute ‘category_set’

But, you can access the parent model Category with the foreign key field category in the child model Product as shown below:

product_obj = Product.objects.all()[0]
category_obj = product_obj.category
                           # ↑ Here
print(category_obj.id, category_obj.name)

Output:

1 Fruits

Leave a comment