Как оптимизировать количество запросов в Django admin для пользовательских полей из другой модели? - PullRequest
1 голос
/ 19 февраля 2020

У меня проблема с SQL оптимизацией запросов для настраиваемого поля list_display "баланс". Для получения баланса счета запрос выполняется для каждой строки. Как избежать этого и исправить количество запросов? Я пытаюсь использовать prefetch_related, но это не имеет никаких эффектов.

class UserAdmin(admin.ModelAdmin):
    form = UserAdminForm
    fields = [
        'username',
        'password',
        'last_name',
        'first_name',
        'middle_name',
        'groups'
    ]
    list_display = [
        'username_',
        'person_name',
        'balance',
    ]

    def balance(self, obj):
        balance = obj.person.customer.customeraccount_set.first().account.balance
        return balance
    balance.allow_tags = True
    balance.short_description = 'Balance'


    def get_queryset(self, request):
        qs = super().get_queryset(request).prefetch_related(
            Prefetch('person__customer__customeraccount_set__account', queryset=CustomerAccount.objects.all()),
            'person', 'person__customer', 'person__customer__customeraccount_set',
        ).filter(groups__name='водитель')
        ordering = self.get_ordering(request)
        if ordering:
            qs = qs.order_by(*ordering)
        return qs

Экран из панели инструментов отладки: enter image description here

1 Ответ

0 голосов
/ 21 февраля 2020

Вы не должны предварительно выбирать целую коллекцию, чтобы показать из нее один элемент. Это также может привести к снижению производительности. Вместо этого используйте подзапрос для извлечения одного свойства из этой коллекции.

from django.db.models import Subquery, OuterRef

class UserAdmin(...):
    ...

    def balance(self, obj):
        balance = obj.customer_account_balance
        return balance
    balance.allow_tags = True
    balance.short_description = 'Balance'


    def get_queryset(self, request):
        qs = super().get_queryset(request).select_related(
            'person', 'person__customer',
        ).filter(groups__name='водитель').annotate(
            customer_account_balance=Subquery(
                CustomerAccount.objects.filter(
                    user_id=OuterRef('id')
                ).order_by(
                    'id' # I don't know how you want to select the balance, but this is where you'd order it.
                ).values('balance')[:1]
            )
        )
        ordering = self.get_ordering(request)
        if ordering:
            qs = qs.order_by(*ordering)
        return qs
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...