Skip to content

Optimize user edit form loading with prefetch_related#1398

Open
Copilot wants to merge 2 commits intomainfrom
copilot/optimize-user-form-loading
Open

Optimize user edit form loading with prefetch_related#1398
Copilot wants to merge 2 commits intomainfrom
copilot/optimize-user-form-loading

Conversation

Copy link
Contributor

Copilot AI commented Mar 10, 2026

O que esse PR faz?

O formulário de edição de usuário na área administrativa carregava lento devido a queries N+1 nas relações M2M (journal, collection, groups, user_permissions). Adicionado prefetch_related no queryset do EditView para resolver.

Onde a revisão poderia começar?

core/users/viewsets.pyCustomUserEditView.get_queryset()

Como este poderia ser testado manualmente?

  1. Acesse a área administrativa → lista de usuários
  2. Clique em um usuário para abrir o formulário de edição
  3. Compare o tempo de carregamento antes e depois (use Django Debug Toolbar ou django.db.connection.queries para confirmar redução de queries)

Algum cenário de contexto que queira dar?

O EditView do Wagtail usa User.objects.get(pk=...) sem nenhum prefetch. Quando o formulário acessa os campos M2M para renderizar os valores selecionados, cada relação gera queries adicionais. O journal em particular precisa de select_related("official") porque Journal.__str__ pode acessar esse FK.

Padrão já utilizado no projeto em IssueAdminSnippetViewSet, SciELOJournalAdminViewSet e FilteredJournalQuerysetMixin.

class CustomUserEditView(WagtailUserEditView):
    def get_queryset(self):
        return User.objects.prefetch_related(
            Prefetch("journal", queryset=Journal.objects.select_related("official")),
            "collection",
            "groups",
            "user_permissions",
        )

Screenshots

N/A — mudança de performance sem impacto visual.

Quais são tickets relevantes?

Referências

Original prompt

This section details on the original issue you should resolve

<issue_title>Melhorar o desempenho da carga do formulário de usuário</issue_title>
<issue_description>### Descrição da tarefa
Melhorar o desempenho da carga do formulário de usuário.
Na área administrativa, acesse a lista de usuários e clique sobre um usuário, ou seja, abra o formulário para editar seus dados. Note que está lento para abrir. Otimize a consulta do banco de dados usando select_related e/oou prefetch_related.</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Co-authored-by: robertatakenaka <505143+robertatakenaka@users.noreply.github.com>
Copilot AI changed the title [WIP] Improve performance of user form loading Optimize user edit form loading with prefetch_related Mar 10, 2026
@robertatakenaka robertatakenaka marked this pull request as ready for review March 10, 2026 21:27
Copilot AI review requested due to automatic review settings March 10, 2026 21:27
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves performance when loading the Wagtail admin user edit form by reducing N+1 queries on the user’s M2M relations (journals, collections, groups, permissions) via an optimized queryset on the edit view.

Changes:

  • Added CustomUserEditView.get_queryset() using prefetch_related() (with a Prefetch for journal using select_related("official")).
  • Wired the custom edit view into the existing UserViewSet via edit_view_class.
  • Added tests to ensure the edit view queryset includes the intended prefetch lookups.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
core/users/viewsets.py Introduces a custom Wagtail user EditView queryset with targeted prefetching to avoid N+1 queries.
core/users/tests/test_views.py Adds coverage asserting the queryset is configured with the expected prefetch relations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +112 to +118
prefetch_lookups = queryset._prefetch_related_lookups
lookup_names = []
for lookup in prefetch_lookups:
if isinstance(lookup, Prefetch):
lookup_names.append(lookup.prefetch_through)
else:
lookup_names.append(lookup)
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test asserts prefetching by reading Django internals (queryset._prefetch_related_lookups and Prefetch.prefetch_through). Those attributes are private/implementation details and can change across Django versions, making the test brittle. Prefer asserting behavior via CaptureQueriesContext (e.g., fetch a user from get_queryset() and ensure iterating user.journal.all() / user.groups.all() does not execute extra queries) or at least use the public Prefetch.prefetch_to attribute instead of prefetch_through.

Copilot uses AI. Check for mistakes.

queryset = view.get_queryset()

assert user in queryset
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assert user in queryset will iterate the whole queryset (and trigger all configured prefetches), which makes the test slower than necessary and can hide issues if more users exist. Prefer a targeted assertion like queryset.filter(pk=user.pk).exists() or queryset.get(pk=user.pk).

Suggested change
assert user in queryset
assert queryset.filter(pk=user.pk).exists()

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Melhorar o desempenho da carga do formulário de usuário

3 participants