Home > Software design >  Does Django is models property hit the database more than once?
Does Django is models property hit the database more than once?

Time:06-08

I've searched in several places but I haven't found a satisfactory answer anywhere.

I have these models:

App bar

    class Bar(models.Model):
        name = models.CharField(max_lenth=50)
        text = models.TextField()

App xyz

    class Xyz(models.Model):
        bar = models.ForeingKey(Bar, on_delete=models.CASCADE, verbose_name='Bar')

App foo

    class Foo(models.Model):
        xyz = models.OneToOneField(Xyz, on_delete=models.CASCADE, verbose_name='Xyz')
        
        def bar_name(self):
            return self.xyz.bar.name

        def bar_text(self):
            return self.xyz.bar.text

My first question is, on self.xyz.bar.name and on self.xyz.bar.text does hit in the database?

If yes, how can i optimize it?


I already tried this, but I'm not sure if it improves anything:

    def bar_name(self):
        return Xyz.objects.select_related('bar').get(pk=self.xyz_id).bar.name

    def bar_text(self):
        return Xyz.objects.select_related('bar').get(pk=self.xyz_id).bar.text

And here comes my second question, using select_related(), I would create a single method like Sigleton pattern, something like this:

    def singleton_bar(self):
        return Xyz.objects.select_related('bar').get(pk=self.xyz_id)

    def bar_name(self):
        return self.singleton_bar().bar.name

    def bar_text(self):
        return self.singleton_bar().bar.text

CodePudding user response:

My first question is, on self.xyz.bar.name and on self.xyz.bar.text does hit in the database?

Yes, given these are not loaded yet by some other query. If you query for self.xyz.bar.name, and xyz is not loaded yet, it will make two queries: one to fetch the xyz object, and one to fetch the bar object referenced by that xyz object.

If you thus access both .bar_name() and .bar_text(), it will not make four queries, since the data is loaded by the first method call, and the second one will "piggy back" on the work already done by the first one.

If yes, how can [I] optimize it?

I would advise not to optimize the queries in the methods, since here you will each time make the same query, as a result with your second approacy, if you call .bar_name() twice, it will two times make the same query. You simply should load the Foo object efficiently. Indeed, you can obtain the foo object with:

foo = Foo.objects.select_related('xyz__bar').get(pk=42)

This will make LEFT OUTER JOINs in the query, to load the related xyz and xyz.bar object in the same query, and thus will result in no extra querying.

  • Related