Optimize user edit form loading with prefetch_related#1398
Optimize user edit form loading with prefetch_related#1398
Conversation
Co-authored-by: robertatakenaka <505143+robertatakenaka@users.noreply.github.com>
There was a problem hiding this comment.
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()usingprefetch_related()(with aPrefetchforjournalusingselect_related("official")). - Wired the custom edit view into the existing
UserViewSetviaedit_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.
| 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) |
There was a problem hiding this comment.
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.
|
|
||
| queryset = view.get_queryset() | ||
|
|
||
| assert user in queryset |
There was a problem hiding this comment.
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).
| assert user in queryset | |
| assert queryset.filter(pk=user.pk).exists() |
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). Adicionadoprefetch_relatedno queryset doEditViewpara resolver.Onde a revisão poderia começar?
core/users/viewsets.py—CustomUserEditView.get_queryset()Como este poderia ser testado manualmente?
django.db.connection.queriespara confirmar redução de queries)Algum cenário de contexto que queira dar?
O
EditViewdo Wagtail usaUser.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. Ojournalem particular precisa deselect_related("official")porqueJournal.__str__pode acessar esse FK.Padrão já utilizado no projeto em
IssueAdminSnippetViewSet,SciELOJournalAdminViewSeteFilteredJournalQuerysetMixin.Screenshots
N/A — mudança de performance sem impacto visual.
Quais são tickets relevantes?
Referências
journal/wagtail_hooks.py(FilteredJournalQuerysetMixin)Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.