prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Site history report n+1s
  While checking Scout APM for a client project with lots of different authors and overall activity, I've noticed that the site history report has a few N+1s.
  
  ![wagtail-log-views-report-n-plus-one](https://user-images.githubusercontent.com/31622/123254960-349a6680-d4e7-11eb-87ec-a0f0ea452c5e.png)
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `wagtail/admin/views/reports/audit_logging.py`
  Content:
  ```
  1 import datetime
  2 
  3 import django_filters
  4 
  5 from django import forms
  6 from django.db.models import Q, Subquery
  7 from django.utils.encoding import force_str
  8 from django.utils.translation import gettext_lazy as _
  9 
  10 from wagtail.admin.filters import DateRangePickerWidget, WagtailFilterSet
  11 from wagtail.core.log_actions import page_log_action_registry
  12 from wagtail.core.models import Page, PageLogEntry, UserPagePermissionsProxy
  13 
  14 from .base import ReportView
  15 
  16 
  17 class SiteHistoryReportFilterSet(WagtailFilterSet):
  18     action = django_filters.ChoiceFilter(choices=page_log_action_registry.get_choices)
  19     hide_commenting_actions = django_filters.BooleanFilter(
  20         label=_('Hide commenting actions'),
  21         method='filter_hide_commenting_actions',
  22         widget=forms.CheckboxInput,
  23     )
  24     timestamp = django_filters.DateFromToRangeFilter(label=_('Date'), widget=DateRangePickerWidget)
  25     label = django_filters.CharFilter(label=_('Title'), lookup_expr='icontains')
  26     user = django_filters.ModelChoiceFilter(
  27         field_name='user', queryset=lambda request: PageLogEntry.objects.all().get_users()
  28     )
  29 
  30     def filter_hide_commenting_actions(self, queryset, name, value):
  31         if value:
  32             queryset = queryset.exclude(
  33                 action__startswith='wagtail.comments'
  34             )
  35         return queryset
  36 
  37     class Meta:
  38         model = PageLogEntry
  39         fields = ['label', 'action', 'user', 'timestamp', 'hide_commenting_actions']
  40 
  41 
  42 class LogEntriesView(ReportView):
  43     template_name = 'wagtailadmin/reports/site_history.html'
  44     title = _('Site history')
  45     header_icon = 'history'
  46     filterset_class = SiteHistoryReportFilterSet
  47 
  48     export_headings = {
  49         "object_id": _("ID"),
  50         "title": _("Title"),
  51         "object_verbose_name": _("Type"),
  52         "action": _("Action type"),
  53         "timestamp": _("Date/Time")
  54     }
  55     list_export = [
  56         "object_id",
  57         "label",
  58         "object_verbose_name",
  59         "action",
  60         "timestamp"
  61     ]
  62 
  63     def __init__(self, **kwargs):
  64         super().__init__(**kwargs)
  65 
  66         self.custom_field_preprocess['action'] = {
  67             self.FORMAT_CSV: self.get_action_label,
  68             self.FORMAT_XLSX: self.get_action_label
  69         }
  70 
  71     def get_filename(self):
  72         return "audit-log-{}".format(
  73             datetime.datetime.today().strftime("%Y-%m-%d")
  74         )
  75 
  76     def get_queryset(self):
  77         q = Q(
  78             page__in=UserPagePermissionsProxy(self.request.user).explorable_pages().values_list('pk', flat=True)
  79         )
  80 
  81         root_page_permissions = Page.get_first_root_node().permissions_for_user(self.request.user)
  82         if (
  83             self.request.user.is_superuser
  84             or root_page_permissions.can_add_subpage() or root_page_permissions.can_edit()
  85         ):
  86             # Include deleted entries
  87             q = q | Q(page_id__in=Subquery(
  88                 PageLogEntry.objects.filter(deleted=True).values('page_id')
  89             ))
  90 
  91         return PageLogEntry.objects.filter(q)
  92 
  93     def get_action_label(self, action):
  94         from wagtail.core.log_actions import page_log_action_registry
  95         return force_str(page_log_action_registry.get_action_label(action))
  96
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/wagtail/admin/views/reports/audit_logging.py b/wagtail/admin/views/reports/audit_logging.py
  --- a/wagtail/admin/views/reports/audit_logging.py
  +++ b/wagtail/admin/views/reports/audit_logging.py
  @@ -74,9 +74,7 @@
           )
   
       def get_queryset(self):
  -        q = Q(
  -            page__in=UserPagePermissionsProxy(self.request.user).explorable_pages().values_list('pk', flat=True)
  -        )
  +        q = Q(page__in=UserPagePermissionsProxy(self.request.user).explorable_pages())
   
           root_page_permissions = Page.get_first_root_node().permissions_for_user(self.request.user)
           if (
  @@ -88,7 +86,11 @@
                   PageLogEntry.objects.filter(deleted=True).values('page_id')
               ))
   
  -        return PageLogEntry.objects.filter(q)
  +        # Using prefech_related() on page, as select_related() generates an INNER JOIN,
  +        # which filters out entries for deleted pages
  +        return PageLogEntry.objects.filter(q).select_related(
  +            'user', 'user__wagtail_userprofile'
  +        ).prefetch_related('page')
   
       def get_action_label(self, action):
           from wagtail.core.log_actions import page_log_action_registry
  
verification_info: {"golden_diff": "diff --git a/wagtail/admin/views/reports/audit_logging.py b/wagtail/admin/views/reports/audit_logging.py\n--- a/wagtail/admin/views/reports/audit_logging.py\n+++ b/wagtail/admin/views/reports/audit_logging.py\n@@ -74,9 +74,7 @@\n         )\n \n     def get_queryset(self):\n-        q = Q(\n-            page__in=UserPagePermissionsProxy(self.request.user).explorable_pages().values_list('pk', flat=True)\n-        )\n+        q = Q(page__in=UserPagePermissionsProxy(self.request.user).explorable_pages())\n \n         root_page_permissions = Page.get_first_root_node().permissions_for_user(self.request.user)\n         if (\n@@ -88,7 +86,11 @@\n                 PageLogEntry.objects.filter(deleted=True).values('page_id')\n             ))\n \n-        return PageLogEntry.objects.filter(q)\n+        # Using prefech_related() on page, as select_related() generates an INNER JOIN,\n+        # which filters out entries for deleted pages\n+        return PageLogEntry.objects.filter(q).select_related(\n+            'user', 'user__wagtail_userprofile'\n+        ).prefetch_related('page')\n \n     def get_action_label(self, action):\n         from wagtail.core.log_actions import page_log_action_registry\n", "issue": "Site history report n+1s\nWhile checking Scout APM for a client project with lots of different authors and overall activity, I've noticed that the site history report has a few N+1s.\r\n\r\n![wagtail-log-views-report-n-plus-one](https://user-images.githubusercontent.com/31622/123254960-349a6680-d4e7-11eb-87ec-a0f0ea452c5e.png)\r\n\n", "before_files": [{"content": "import datetime\n\nimport django_filters\n\nfrom django import forms\nfrom django.db.models import Q, Subquery\nfrom django.utils.encoding import force_str\nfrom django.utils.translation import gettext_lazy as _\n\nfrom wagtail.admin.filters import DateRangePickerWidget, WagtailFilterSet\nfrom wagtail.core.log_actions import page_log_action_registry\nfrom wagtail.core.models import Page, PageLogEntry, UserPagePermissionsProxy\n\nfrom .base import ReportView\n\n\nclass SiteHistoryReportFilterSet(WagtailFilterSet):\n    action = django_filters.ChoiceFilter(choices=page_log_action_registry.get_choices)\n    hide_commenting_actions = django_filters.BooleanFilter(\n        label=_('Hide commenting actions'),\n        method='filter_hide_commenting_actions',\n        widget=forms.CheckboxInput,\n    )\n    timestamp = django_filters.DateFromToRangeFilter(label=_('Date'), widget=DateRangePickerWidget)\n    label = django_filters.CharFilter(label=_('Title'), lookup_expr='icontains')\n    user = django_filters.ModelChoiceFilter(\n        field_name='user', queryset=lambda request: PageLogEntry.objects.all().get_users()\n    )\n\n    def filter_hide_commenting_actions(self, queryset, name, value):\n        if value:\n            queryset = queryset.exclude(\n                action__startswith='wagtail.comments'\n            )\n        return queryset\n\n    class Meta:\n        model = PageLogEntry\n        fields = ['label', 'action', 'user', 'timestamp', 'hide_commenting_actions']\n\n\nclass LogEntriesView(ReportView):\n    template_name = 'wagtailadmin/reports/site_history.html'\n    title = _('Site history')\n    header_icon = 'history'\n    filterset_class = SiteHistoryReportFilterSet\n\n    export_headings = {\n        \"object_id\": _(\"ID\"),\n        \"title\": _(\"Title\"),\n        \"object_verbose_name\": _(\"Type\"),\n        \"action\": _(\"Action type\"),\n        \"timestamp\": _(\"Date/Time\")\n    }\n    list_export = [\n        \"object_id\",\n        \"label\",\n        \"object_verbose_name\",\n        \"action\",\n        \"timestamp\"\n    ]\n\n    def __init__(self, **kwargs):\n        super().__init__(**kwargs)\n\n        self.custom_field_preprocess['action'] = {\n            self.FORMAT_CSV: self.get_action_label,\n            self.FORMAT_XLSX: self.get_action_label\n        }\n\n    def get_filename(self):\n        return \"audit-log-{}\".format(\n            datetime.datetime.today().strftime(\"%Y-%m-%d\")\n        )\n\n    def get_queryset(self):\n        q = Q(\n            page__in=UserPagePermissionsProxy(self.request.user).explorable_pages().values_list('pk', flat=True)\n        )\n\n        root_page_permissions = Page.get_first_root_node().permissions_for_user(self.request.user)\n        if (\n            self.request.user.is_superuser\n            or root_page_permissions.can_add_subpage() or root_page_permissions.can_edit()\n        ):\n            # Include deleted entries\n            q = q | Q(page_id__in=Subquery(\n                PageLogEntry.objects.filter(deleted=True).values('page_id')\n            ))\n\n        return PageLogEntry.objects.filter(q)\n\n    def get_action_label(self, action):\n        from wagtail.core.log_actions import page_log_action_registry\n        return force_str(page_log_action_registry.get_action_label(action))\n", "path": "wagtail/admin/views/reports/audit_logging.py"}], "after_files": [{"content": "import datetime\n\nimport django_filters\n\nfrom django import forms\nfrom django.db.models import Q, Subquery\nfrom django.utils.encoding import force_str\nfrom django.utils.translation import gettext_lazy as _\n\nfrom wagtail.admin.filters import DateRangePickerWidget, WagtailFilterSet\nfrom wagtail.core.log_actions import page_log_action_registry\nfrom wagtail.core.models import Page, PageLogEntry, UserPagePermissionsProxy\n\nfrom .base import ReportView\n\n\nclass SiteHistoryReportFilterSet(WagtailFilterSet):\n    action = django_filters.ChoiceFilter(choices=page_log_action_registry.get_choices)\n    hide_commenting_actions = django_filters.BooleanFilter(\n        label=_('Hide commenting actions'),\n        method='filter_hide_commenting_actions',\n        widget=forms.CheckboxInput,\n    )\n    timestamp = django_filters.DateFromToRangeFilter(label=_('Date'), widget=DateRangePickerWidget)\n    label = django_filters.CharFilter(label=_('Title'), lookup_expr='icontains')\n    user = django_filters.ModelChoiceFilter(\n        field_name='user', queryset=lambda request: PageLogEntry.objects.all().get_users()\n    )\n\n    def filter_hide_commenting_actions(self, queryset, name, value):\n        if value:\n            queryset = queryset.exclude(\n                action__startswith='wagtail.comments'\n            )\n        return queryset\n\n    class Meta:\n        model = PageLogEntry\n        fields = ['label', 'action', 'user', 'timestamp', 'hide_commenting_actions']\n\n\nclass LogEntriesView(ReportView):\n    template_name = 'wagtailadmin/reports/site_history.html'\n    title = _('Site history')\n    header_icon = 'history'\n    filterset_class = SiteHistoryReportFilterSet\n\n    export_headings = {\n        \"object_id\": _(\"ID\"),\n        \"title\": _(\"Title\"),\n        \"object_verbose_name\": _(\"Type\"),\n        \"action\": _(\"Action type\"),\n        \"timestamp\": _(\"Date/Time\")\n    }\n    list_export = [\n        \"object_id\",\n        \"label\",\n        \"object_verbose_name\",\n        \"action\",\n        \"timestamp\"\n    ]\n\n    def __init__(self, **kwargs):\n        super().__init__(**kwargs)\n\n        self.custom_field_preprocess['action'] = {\n            self.FORMAT_CSV: self.get_action_label,\n            self.FORMAT_XLSX: self.get_action_label\n        }\n\n    def get_filename(self):\n        return \"audit-log-{}\".format(\n            datetime.datetime.today().strftime(\"%Y-%m-%d\")\n        )\n\n    def get_queryset(self):\n        q = Q(page__in=UserPagePermissionsProxy(self.request.user).explorable_pages())\n\n        root_page_permissions = Page.get_first_root_node().permissions_for_user(self.request.user)\n        if (\n            self.request.user.is_superuser\n            or root_page_permissions.can_add_subpage() or root_page_permissions.can_edit()\n        ):\n            # Include deleted entries\n            q = q | Q(page_id__in=Subquery(\n                PageLogEntry.objects.filter(deleted=True).values('page_id')\n            ))\n\n        # Using prefech_related() on page, as select_related() generates an INNER JOIN,\n        # which filters out entries for deleted pages\n        return PageLogEntry.objects.filter(q).select_related(\n            'user', 'user__wagtail_userprofile'\n        ).prefetch_related('page')\n\n    def get_action_label(self, action):\n        from wagtail.core.log_actions import page_log_action_registry\n        return force_str(page_log_action_registry.get_action_label(action))\n", "path": "wagtail/admin/views/reports/audit_logging.py"}]}