Skip to content

Commit

Permalink
Avoid N+1 queries in users index view
Browse files Browse the repository at this point in the history
  • Loading branch information
Tijani-Dia authored and laymonage committed Jul 17, 2023
1 parent 71d19a7 commit a6c9409
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Changelog
* Fix: Improve visibility of scheduled publishing errors in status side panel (Sage Abdullah)
* Fix: Prevent 'choose' permission from being ignored when looking up 'choose', 'edit' and 'delete' permissions in combination (Sage Abdullah)
* Fix: Take user's permissions into account for image / document counts on the admin dashboard (Sage Abdullah)
* Fix: Avoid N+1 queries in users index view (Tidiane Dia)
* Docs: Document how to add non-ModelAdmin views to a `ModelAdminGroup` (Onno Timmerman)
* Docs: Document how to add StructBlock data to a StreamField (Ramon Wenger)
* Docs: Update ReadTheDocs settings to v2 to resolve urllib3 issue in linkcheck extension (Thibaud Colas)
Expand Down
1 change: 1 addition & 0 deletions docs/releases/5.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ This feature was developed by Aman Pandey as part of the Google Summer of Code p
* Improve visibility of scheduled publishing errors in status side panel (Sage Abdullah)
* Prevent 'choose' permission from being ignored when looking up 'choose', 'edit' and 'delete' permissions in combination (Sage Abdullah)
* Take user's permissions into account for image / document counts on the admin dashboard (Sage Abdullah)
* Avoid N+1 queries in users index view (Tidiane Dia)

### Documentation

Expand Down
13 changes: 13 additions & 0 deletions wagtail/users/tests/test_admin_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,19 @@ def test_valid_ordering(self):
response = self.get({"ordering": "username"})
self.assertEqual(response.context_data["ordering"], "username")

def test_num_queries(self):
# Warm up
self.get()

num_queries = 9
with self.assertNumQueries(num_queries):
self.get()

# Ensure we don't have any N+1 queries
self.create_user("test", "test@example.com", "gu@rd14n")
with self.assertNumQueries(num_queries):
self.get()


class TestUserIndexResultsView(WagtailTestUtils, TestCase):
def setUp(self):
Expand Down
2 changes: 1 addition & 1 deletion wagtail/users/views/bulk_actions/user_bulk_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def get_all_objects_in_listing_query(self, parent_id):
listing_objects = self.model.objects.all().values_list("pk", flat=True)
if "q" in self.request.GET:
q = self.request.GET.get("q")
model_fields = [f.name for f in self.model._meta.get_fields()]
model_fields = {f.name for f in self.model._meta.get_fields()}
conditions = get_users_filter_query(q, model_fields)

listing_objects = listing_objects.filter(conditions)
Expand Down
11 changes: 8 additions & 3 deletions wagtail/users/views/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,12 @@ class Index(IndexView):
is_searchable = True
page_title = gettext_lazy("Users")

model_fields = [f.name for f in User._meta.get_fields()]

def setup(self, request, *args, **kwargs):
super().setup(request, *args, **kwargs)
self.group = get_object_or_404(Group, id=args[0]) if args else None
self.group_filter = Q(groups=self.group) if self.group else Q()
self.model_fields = [f.name for f in User._meta.get_fields()]

def get_index_results_url(self):
if self.group:
Expand All @@ -99,16 +100,20 @@ def get_valid_orderings(self):
return ["name", "username"]

def get_queryset(self):
model_fields = set(self.model_fields)
if self.is_searching:
conditions = get_users_filter_query(self.search_query, self.model_fields)
conditions = get_users_filter_query(self.search_query, model_fields)
users = User.objects.filter(self.group_filter & conditions)
else:
users = User.objects.filter(self.group_filter)

if self.locale:
users = users.filter(locale=self.locale)

if "last_name" in self.model_fields and "first_name" in self.model_fields:
if "wagtail_userprofile" in model_fields:
users = users.select_related("wagtail_userprofile")

if "last_name" in model_fields and "first_name" in model_fields:
users = users.order_by("last_name", "first_name")

if self.get_ordering() == "username":
Expand Down

0 comments on commit a6c9409

Please sign in to comment.