Использование внешнего ключа в качестве столбца в интерфейсе администратора django создает новый запрос к базе данных для каждой строки?

У меня есть модель отношений, которая выглядит следующим образом:

class Author(Model):
    first_name = CharField()

class Book(Model):
    title = CharField()
    author = ForeignKey(Author)

Я хочу иметь такой интерфейс администратора:

class BookAdmin(ModelAdmin):
    list_display = ('title', 'author_name')

    def author_name(self, obj):
        return obj.author.name

Создается ли при этом новый запрос для каждой строки, или django разумно использует здесь join? Что если отношение имеет глубину в 2 или более уровней, а не только 1?

Использую python 3.8, django 3.1, и Postgres 12.

Смотрите FAQ по документации: "Как я могу увидеть необработанные SQL-запросы, которые выполняет Django? "

Убедитесь, что ваш параметр Django DEBUG установлен на True. Затем сделайте следующее:

from django.db import connection
print(connection.queries)

Это дает вам все SQL-запросы, которые выполнил Django. Отсюда вы можете проверить, использует ли он джойны или отдельный запрос для ForeignKey

Только что протестировал это, и да, похоже, что создается новый запрос для каждой строки. Для подтверждения, вы можете использовать DEBUG = True в настройках и сделать что-то вроде этого:

class BookAdmin(ModelAdmin):
    list_display = ('title', 'author_name')

    def author_name(self, obj):
        name = obj.author.name
        from django.db import connection
        print(len(connection.queries))
        return name

Здесь будет выведено количество запросов, выполняемых в момент отображения строки. Вы можете заметить, что оно увеличивается по мере отображения строк.

К счастью, вы можете переопределить get_queryset, чтобы добавить select_related, для улучшения запросов, так:

class BookAdmin(ModelAdmin):
    list_display = ('title', 'author_name')

    def get_queryset(self, request):
        queryset = super().get_queryset(request)
        return queryset.select_related('author')

    def author_name(self, obj):
        return obj.author.name

Это дало мне постоянное количество запросов, что идеально.

Вернуться на верх