Repository: wagtail/wagtail

Issue:
Locked pages report renders all users in "locked_by" filter
### Issue Summary

Currently, the select-field for the "locked_by" filter on the "Locked pages"-report renders all users unfiltered from the user table.
This breaks the view for one of our projects, which tries to list all 500k users...
Actually, only the users which have locked a page should be listed.

I will try to make a PR for that, in the meantime this quickfix works for us (with wagtail 4.0, django 3.2):
```python
# in one of our apps.py
from django.apps import AppConfig

class BaseConfig(AppConfig):
    name = "base"

    def ready(self):
        patch_locked_pages_filter()

def patch_locked_pages_filter():
    import django_filters
    from django.contrib.auth import get_user_model

    from wagtail.admin.views.reports.locked_pages import LockedPagesView, LockedPagesReportFilterSet

    def get_users_for_filter():
        User = get_user_model()
        return User.objects.filter(locked_pages__isnull=False).order_by(User.USERNAME_FIELD)

    class PatchedLockedPagesReportFilterSet(LockedPagesReportFilterSet):
        locked_by = django_filters.ModelChoiceFilter(
            field_name="locked_by", queryset=lambda request: get_users_for_filter()
        )

    LockedPagesView.filterset_class = PatchedLockedPagesReportFilterSet

```

### Steps to Reproduce

1. Start a new project with `wagtail start myproject`
2. Create many users, no matter if they have access to the CMS or not
3. Open `/admin/reports/locked/` and find all those users in the "locked_by" dropdown on the right

-   I have confirmed that this issue can be reproduced as described on a fresh Wagtail project: yes

### Technical details

-   Python version: 3.10
-   Django version: 3.2
-   Wagtail version: 4.0, 2.15,... (according to the git history seems to be there from the beginning)



Discussion:

Resolving patch:
diff --git a/wagtail/admin/views/reports/locked_pages.py b/wagtail/admin/views/reports/locked_pages.py
--- a/wagtail/admin/views/reports/locked_pages.py
+++ b/wagtail/admin/views/reports/locked_pages.py
@@ -2,6 +2,7 @@
 
 import django_filters
 from django.conf import settings
+from django.contrib.auth import get_user_model
 from django.core.exceptions import PermissionDenied
 from django.utils.translation import gettext_lazy as _
 
@@ -11,8 +12,16 @@
 from .base import PageReportView
 
 
+def get_users_for_filter():
+    User = get_user_model()
+    return User.objects.filter(locked_pages__isnull=False).order_by(User.USERNAME_FIELD)
+
+
 class LockedPagesReportFilterSet(WagtailFilterSet):
     locked_at = django_filters.DateFromToRangeFilter(widget=DateRangePickerWidget)
+    locked_by = django_filters.ModelChoiceFilter(
+        field_name="locked_by", queryset=lambda request: get_users_for_filter()
+    )
 
     class Meta:
         model = Page


Test patch:
diff --git a/wagtail/admin/tests/test_reports_views.py b/wagtail/admin/tests/test_reports_views.py
--- a/wagtail/admin/tests/test_reports_views.py
+++ b/wagtail/admin/tests/test_reports_views.py
@@ -30,6 +30,16 @@ def test_simple(self):
         # Initially there should be no locked pages
         self.assertContains(response, "No locked pages found.")
 
+        # No user locked anything
+        self.assertInHTML(
+            """
+            <select name="locked_by" id="id_locked_by">
+                <option value="" selected>---------</option>
+            </select>
+            """,
+            response.content.decode(),
+        )
+
         self.page = Page.objects.first()
         self.page.locked = True
         self.page.locked_by = self.user
@@ -43,6 +53,16 @@ def test_simple(self):
         self.assertNotContains(response, "No locked pages found.")
         self.assertContains(response, self.page.title)
 
+        self.assertInHTML(
+            f"""
+            <select name="locked_by" id="id_locked_by">
+                <option value="" selected>---------</option>
+                <option value="{self.user.pk}">{self.user}</option>
+            </select>
+            """,
+            response.content.decode(),
+        )
+
     def test_csv_export(self):
 
         self.page = Page.objects.first()