Сведите к минимуму количество запросов в администраторе модели Django

#django #django-models #django-admin

Вопрос:

Предположим, у меня есть две модели 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)
 

файл администратора для Model1, как,

 @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
 

когда я получаю связанные поля модели с помощью метода в list_display, он повторяет один и тот же запрос несколько раз (list_per_page * no_of_fields_by_method, который в текущем случае равен 40).

Я не хочу соединять model1 с model2, потому что model1 уже соединяется с другими моделями, и мы знаем, что запрос Count() займет время, если у нас большие таблицы.

Мой вопрос в том , есть ли какой-либо другой способ получить переназначенные объекты модели без повторения одного и того же запроса? (означает только 10-кратный запрос вместо 40-кратного одного и того же запроса в текущем случае.)

Ответ №1:

Я не совсем уверен, передает ли администратор тот же объект obj методам ( def get_field1(self, obj): ), но если это так, то вы можете попробовать использовать cached_property декоратор.

В моделях добавьте метод с этим декоратором, чтобы этот метод запрашивал базу данных только один раз за время существования этого объекта:

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

и попробуйте использовать это в администраторе:

 @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
    ...