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)

Number of SQL queries

Asked By: Kirill_N

||

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

Answered By: Michał
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.