Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to select related in django model so it wont generate a lot of subqueries

I have lot of models that are referring to each other in some way, for example:

Port is referring to City, which in its turn refers to Country. Then in django admin I want to show in list_display Ports country:

class Country(models.Model):
    title = models.CharField()


class City(models.Model):
    title = models.CharField()

    country = models.ForeignKey(Country)


class Port(models.Model):
    city = models.ForeignKey(City)

    def __str__(self):
        return self.city.county.title

So basically for each port django is generating more queries. I assume that select_related would help me somehow in this case, but how to use it properly within the model?

like image 915
Dmitrijs Zubriks Avatar asked Dec 08 '16 09:12

Dmitrijs Zubriks


People also ask

What is the use of select related in Django?

In Django, select_related and prefetch_related are designed to stop the deluge of database queries that are caused by accessing related objects. In this article, we will see how it reduces the number of queries and make the program much faster.

What is __ str __ In Django model?

The __str__() method is called whenever you call str() on an object. Django uses str(obj) in a number of places. Most notably, to display an object in the Django admin site and as the value inserted into a template when it displays an object.


2 Answers

You can create a PortManager class and override get_queryset method and reference it in the model:

class PortManager(models.Manager):
    def get_queryset(self):
        return super(PortManager, self).get_queryset().select_related()


class Port(models.Model):
    city = models.ForeignKey(City)
    objects = PortManager()

    def __str__(self):
        return self.city.country.title
like image 63
Ivan Avatar answered Oct 17 '22 18:10

Ivan


Based on Ivan's answer, I came up with the following structure for multiple models related with "one to many" and "many to many" relations using select_related and prefetch_related accordingly.

In the provided example only select_related is required.

class Country(models.Model):
    title = models.CharField()

    def __str__(self):
        return '{0}'.format(self.title)


class CityManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().select_related('country')


class City(models.Model):
    title = models.CharField()
    country = models.ForeignKey(Country)
    objects = CityManager()

    def __str__(self):
        return '{0}-{1}'.format(
            self.title,
            self.country.__str__(),
        )


class PortManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().select_related('city')


class Port(models.Model):
    city = models.ForeignKey(City)
    objects = PortManager()

    def __str__(self):
        return self.city.__str__()
like image 44
raratiru Avatar answered Oct 17 '22 19:10

raratiru