Home > Net >  Minimize Number of Queries in Django Model Admin
Minimize Number of Queries in Django Model Admin

Time:10-01

Suppose I have two models ModelA, ModelB,

class Model1(models.Model):
    # multple model fields, also contains foreign key
    
class Model2(models.Model):
    model1_id = models.ForeignKey(Model1, models.DO_NOTHING)
    # other model fields
    field1 = models.IntegerField()
    field2 = models.ForeignKey()
    field3 = models.CharField(max_length=50)
    field4 = models.DateTimeField(blank=True, null=True)

admin file for Model1 like,

@admin.register(Model1)
class Model1Admin(admin.ModelAdmin):

    list_per_page = 10

    list_display = ['some_model1_fields', 'get_field1','get_field2', 'get_field3', 'get_field4']

    def get_field1(self, obj):
        return obj.model2_set.last().field1

    def get_field2(self, obj):
        return obj.model2_set.last().field2

    def get_field3(self, obj):
        return obj.model2_set.last().field3

    def get_field4(self, obj):
        return obj.model2_set.last().field4

when I get related model fields using method in list_display, it repeats same query multiple time (list_per_page * no_of_fields_by_method which is 40 in current case).

I don't want to join model1 with model2 because model1 already join with other models and we know Count() query will takes time if we have large tables.

My question is , Is any other way to get releted model objects without repeat the same query? (means only 10 times query instead of 40 times same query in current case.)

CodePudding user response:

I am not exactly sure, if the admin passes the same object obj to the methods (def get_field1(self, obj):), but if it does, then you could try using the cached_property decorator.

In models add a method with this decorator, so that this method will query the database only once for the lifetime of this object:

class Model1(models.Model):
    ...
    @cached_property
    def cached_last_model2(self):
        return self.model2_set.last()

and try using this in the admin:

@admin.register(Model1)
class Model1Admin(admin.ModelAdmin):
    ...
    def get_field1(self, obj):
        return obj.cached_last_model2.field1

    def get_field2(self, obj):
        return obj.cached_last_model2.field2
    ...
  • Related