DEV Community

guzmanojero
guzmanojero

Posted on

Can you use select_related and prefetch_related with Abstract Base Classes in Django?

Yes!! Here you have an example πŸ‘‡

You can use QuerySet.prefetch_related or QuerySet.select_related with Abstract Base Classes in Django.

Let's say we have these models:


class Country(models.Model):
    name = models.CharField(max_length=200)

    def __str__(self):
        return self.name

class AbstractPerson(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

    class Meta:
        abstract = True

class AbstractAddress(models.Model):
    street = models.CharField(max_length=100)
    city = models.CharField(max_length=50)
    state = models.CharField(max_length=2)
    zip_code = models.CharField(max_length=10)
    country = models.ForeignKey(Country, on_delete=models.CASCADE)

    class Meta:
        abstract = True

class AbstractPhoneNumber(models.Model):
    phone_number = models.CharField(max_length=15)

    class Meta:
        abstract = True

class Contact(AbstractPerson, AbstractAddress, AbstractPhoneNumber):
    email = models.EmailField()

    def __str__(self):
        return f"{self.first_name} {self.last_name} - {self.country}"
Enter fullscreen mode Exit fullscreen mode

If you make this query you wouldn't have a N+1 issue:

> Contact.objects.select_related("country").get(id=1).country
Enter fullscreen mode Exit fullscreen mode

You have one query only. The generated SQL is:

SELECT app_contact.id,
       app_contact.first_name,
       app_contact.last_name,
       app_contact.street,
       app_contact.city,
       app_contact.state,
       app_contact.zip_code,
       app_contact.country_id,
       app_contact.phone_number,
       app_contact.email,
       app_country.id,
       app_country.name
  FROM app_contact
INNER JOIN app_country
    ON (app_contact.country_id = app_country.id)
 WHERE app_contact.id = '1'
Enter fullscreen mode Exit fullscreen mode

Top comments (0)