Минимизация количества запросов в Django Model 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).
Я не хочу соединять модель1 с моделью2, потому что модель1 уже соединяется с другими моделями, и мы знаем, что запрос Count() займет много времени, если у нас большие таблицы.
Мой вопрос в том, есть ли другой способ получить удаленные объекты модели без повторения одного и того же запроса? (имеется в виду только 10 раз запрос вместо 40 раз одного и того же запроса в текущем случае)
Я не совсем уверен, передает ли админ один и тот же объект 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
...