Is select_related() still needed after defining only() in django query

Viewed 63

select_related is used so whenever a defined foreign key accessed, it will be included in the first query and won't issue another query to db. But I have a case when only few fields are needed. Here is the example

class PMapKomoditi(models.Model):
    id = models.IntegerField(primary_key=True)
    komoditi_fk = models.ForeignKey(PMastKomoditi, models.RESTRICT, db_column='id_komoditi')
    kd_komoditi = models.CharField(max_length=2)
    nm_komoditi = models.CharField(max_length=50, blank=True, null=True)
    uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
    // ...


class PMastKomoditi(models.Model):
    id = models.AutoField(primary_key=True)
    uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
    // ...

I only need kd_komoditi & komoditi_fk properties, so I do query the following:

my_query = PMapKomoditi.objects.select_related(
    'komoditi_fk'
).Only(
    'kd_komoditi',
    'komoditi_fk'
)

Do I need to include the select_related or it's already covered with only()?

2 Answers

Great question! And I don't know the answer! But you can find out by using the "query" attribute of your query set.

my_query = PMapKomoditi.objects.select_related('komoditi_fk').only('kd_komoditi','komoditi_fk')
print(my_query.query)

test_query = PMapKomoditi.objects.only('kd_komoditi','komoditi_fk')
print(test_query.query)

That will tell you what's going on "under the covers".

No only will not make a join like select_related does. So you cannot replace select_related by only. Furthermore the field referred to by select_related must also be part of the call to only if you are using it and cannot be deferred. You can also add related fields to the only call if you want to select only few of the related models fields.

Moving further when in doubt one should simply check the SQL query generated by the ORM:

my_query = PMapKomoditi.objects.select_related(
    'komoditi_fk'
).only(
    'kd_komoditi',
    'komoditi_fk'
)

print(my_query.query) # Performs an INNER JOIN


my_query2 = PMapKomoditi.objects.only(
    'kd_komoditi',
    'komoditi_fk'
)

print(my_query2.query) # No INNER JOIN
Related