How to remove all duplicates and similiar queries from Django admin
Question:
I have a lot different models in my project and in every of them there’s a duplicated SQL queries
I want to know how to remove them but the main problem is that in one model when I’m trying to take a look on single object of this model I have like 5k SQL queries.
I also tried to for loop all of information from this model in my template and still got ~5k queries how does it work?
models.py
class PresenceSectionList(models.Model):
presence_detail = models.ForeignKey(PresenceDetailInfo, on_delete=models.CASCADE)
presence_sections = models.ForeignKey(CleanSections, blank=True, on_delete=models.CASCADE, null=True)
class Meta:
verbose_name = 'Раздел с информацией'
verbose_name_plural = 'Разделы с информацией'
ordering = ['presence_detail', ]
def __str__(self):
return f'{self.presence_detail}'
class CleanSections(models.Model):
GUID = models.UUIDField(default=uuid.uuid4, editable=True, unique=True)
name = models.CharField(max_length=120, verbose_name='Краткое наименование')
details = models.CharField(max_length=300, verbose_name='Описание', blank=True)
class ObjectList(models.Model):
GUID = models.UUIDField(default=uuid.uuid4, editable=True, unique=True)
name = models.CharField(max_length=250, verbose_name='Наименование')
customer_guid = models.ForeignKey(CounterParty, related_name='customer_guid', on_delete=models.CASCADE,
verbose_name='Наименование заказчика', default=None, blank=True, null=True)
contractor_guid = models.ManyToManyField(CounterParty, related_name='contractor_guid',
verbose_name='Наименование подрядчика', default=None, blank=True)
sections = models.ManyToManyField('SectionList', default=None, related_name='section', verbose_name='Разделы',
blank=True)
class CounterParty(models.Model):
GUID = models.UUIDField(default=uuid.uuid4, editable=True, unique=True)
name = models.CharField(max_length=150, verbose_name='Наименование')
customer = models.BooleanField(default=False, verbose_name='Заказчик')
contractor = models.BooleanField(default=False, verbose_name='Подрядчик')
counter_user = models.ManyToManyField(User, blank=True, related_name='counter_user',
verbose_name='Пользователи контрагента')
admin.py
class PresenceSectionListAdmin(admin.ModelAdmin):
list_display = ('presence_detail', 'presence_sections')
ordering = ['presence_detail__presence_info', 'presence_detail__work_date']
admin.site.register(PresenceSectionList, PresenceSectionListAdmin)
Answers:
When Django Admin loads a list of PresenceSectionList
objects, then it accesses two attributes: presence_detail
and presence_sections
on each object. Since these fields are relations, then Django needs to fetch one PresenceDetailInfo
and one CleanSections
object per each PresenceSectionList
.
This is very inefficient way. It would be much better to use .select_related() QuerySet’s method. This will fetch the main model and related models in one query.
In django admin you need to override get_queryset()
method:
In your PresenceSectionListAdmin
class, add:
def get_queryset(request):
base_qs = super().get_queryset(request)
return base_qs.select_related("presence_detail", "presence_sections")
This should reduce number of queries.
PS. I can also see many duplicated queries FROM common_counterpart
in your screenshot, which I can’t see in your example code. You can try select_related or prefetch_related (in case of m2m relations.)
I have a lot different models in my project and in every of them there’s a duplicated SQL queries
I want to know how to remove them but the main problem is that in one model when I’m trying to take a look on single object of this model I have like 5k SQL queries.
I also tried to for loop all of information from this model in my template and still got ~5k queries how does it work?
models.py
class PresenceSectionList(models.Model):
presence_detail = models.ForeignKey(PresenceDetailInfo, on_delete=models.CASCADE)
presence_sections = models.ForeignKey(CleanSections, blank=True, on_delete=models.CASCADE, null=True)
class Meta:
verbose_name = 'Раздел с информацией'
verbose_name_plural = 'Разделы с информацией'
ordering = ['presence_detail', ]
def __str__(self):
return f'{self.presence_detail}'
class CleanSections(models.Model):
GUID = models.UUIDField(default=uuid.uuid4, editable=True, unique=True)
name = models.CharField(max_length=120, verbose_name='Краткое наименование')
details = models.CharField(max_length=300, verbose_name='Описание', blank=True)
class ObjectList(models.Model):
GUID = models.UUIDField(default=uuid.uuid4, editable=True, unique=True)
name = models.CharField(max_length=250, verbose_name='Наименование')
customer_guid = models.ForeignKey(CounterParty, related_name='customer_guid', on_delete=models.CASCADE,
verbose_name='Наименование заказчика', default=None, blank=True, null=True)
contractor_guid = models.ManyToManyField(CounterParty, related_name='contractor_guid',
verbose_name='Наименование подрядчика', default=None, blank=True)
sections = models.ManyToManyField('SectionList', default=None, related_name='section', verbose_name='Разделы',
blank=True)
class CounterParty(models.Model):
GUID = models.UUIDField(default=uuid.uuid4, editable=True, unique=True)
name = models.CharField(max_length=150, verbose_name='Наименование')
customer = models.BooleanField(default=False, verbose_name='Заказчик')
contractor = models.BooleanField(default=False, verbose_name='Подрядчик')
counter_user = models.ManyToManyField(User, blank=True, related_name='counter_user',
verbose_name='Пользователи контрагента')
admin.py
class PresenceSectionListAdmin(admin.ModelAdmin):
list_display = ('presence_detail', 'presence_sections')
ordering = ['presence_detail__presence_info', 'presence_detail__work_date']
admin.site.register(PresenceSectionList, PresenceSectionListAdmin)
When Django Admin loads a list of PresenceSectionList
objects, then it accesses two attributes: presence_detail
and presence_sections
on each object. Since these fields are relations, then Django needs to fetch one PresenceDetailInfo
and one CleanSections
object per each PresenceSectionList
.
This is very inefficient way. It would be much better to use .select_related() QuerySet’s method. This will fetch the main model and related models in one query.
In django admin you need to override get_queryset()
method:
In your PresenceSectionListAdmin
class, add:
def get_queryset(request):
base_qs = super().get_queryset(request)
return base_qs.select_related("presence_detail", "presence_sections")
This should reduce number of queries.
PS. I can also see many duplicated queries FROM common_counterpart
in your screenshot, which I can’t see in your example code. You can try select_related or prefetch_related (in case of m2m relations.)