prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Albums pagination doesn't maintain search terms
  ### Describe the bug
  If you open https://thalia.nu/members/photos/?keywords=borrel#photos-albums, then go to the second page using the pagination buttons, the search term is dropped.
  
  ### Expected behaviour
  <!-- A clear and concise description of what you expected to happen. -->
  The search term remains
  
  ### Additional context
  <!-- Add any other context about the problem here. -->
  Could be since we introduced the shared paginated view template? So it's quite likely this occurs for other paginated filterable/searchable views as well.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `website/thaliawebsite/views.py`
  Content:
  ```
  1 """General views for the website."""
  2 
  3 from django.contrib.admin.views.decorators import staff_member_required
  4 from django.contrib.auth.views import LoginView, PasswordResetView
  5 from django.core.exceptions import PermissionDenied
  6 from django.http import HttpResponse, HttpResponseForbidden
  7 from django.shortcuts import redirect
  8 from django.utils.decorators import method_decorator
  9 from django.views.generic import ListView, TemplateView
  10 from django.views.generic.base import View
  11 
  12 from django_ratelimit.decorators import ratelimit
  13 
  14 
  15 class IndexView(TemplateView):
  16     template_name = "index.html"
  17 
  18 
  19 @method_decorator(staff_member_required, "dispatch")
  20 class TestCrashView(View):
  21     """Test view to intentionally crash to test the error handling."""
  22 
  23     def dispatch(self, request, *args, **kwargs) -> HttpResponse:
  24         if not request.user.is_superuser:
  25             return HttpResponseForbidden("This is not for you")
  26         raise Exception("Test exception")
  27 
  28 
  29 class PagedView(ListView):
  30     """A ListView with automatic pagination."""
  31 
  32     def get_context_data(self, **kwargs) -> dict:
  33         context = super().get_context_data(**kwargs)
  34         page = context["page_obj"].number
  35         paginator = context["paginator"]
  36 
  37         # Show the two pages before and after the current page
  38         page_range_start = max(1, page - 2)
  39         page_range_stop = min(page + 3, paginator.num_pages + 1)
  40 
  41         # Add extra pages if we show less than 5 pages
  42         page_range_start = min(page_range_start, page_range_stop - 5)
  43         page_range_start = max(1, page_range_start)
  44 
  45         # Add extra pages if we still show less than 5 pages
  46         page_range_stop = max(page_range_stop, page_range_start + 5)
  47         page_range_stop = min(page_range_stop, paginator.num_pages + 1)
  48 
  49         page_range = range(page_range_start, page_range_stop)
  50 
  51         context.update(
  52             {
  53                 "page_range": page_range,
  54             }
  55         )
  56 
  57         return context
  58 
  59 
  60 class RateLimitedPasswordResetView(PasswordResetView):
  61     @method_decorator(ratelimit(key="ip", rate="5/h"))
  62     def post(self, request, *args, **kwargs):
  63         return super().post(request, *args, **kwargs)
  64 
  65 
  66 class RateLimitedLoginView(LoginView):
  67     @method_decorator(ratelimit(key="ip", rate="30/h"))
  68     @method_decorator(ratelimit(key="post:username", rate="30/h"))
  69     def post(self, request, *args, **kwargs):
  70         return super().post(request, *args, **kwargs)
  71 
  72 
  73 def rate_limited_view(request, *args, **kwargs):
  74     return HttpResponse("You are rate limited", status=429)
  75 
  76 
  77 def admin_unauthorized_view(request):
  78     if not request.member:
  79         url = "/user/login"
  80         args = request.META.get("QUERY_STRING", "")
  81         if args:
  82             url = f"{url}?{args}"
  83         return redirect(url)
  84     elif not request.member.is_staff and not request.member.is_superuser:
  85         raise PermissionDenied("You are not allowed to access the administration page.")
  86     else:
  87         return redirect(request.GET.get("next", "/"))
  88
  ```
  --- 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/website/thaliawebsite/views.py b/website/thaliawebsite/views.py
  --- a/website/thaliawebsite/views.py
  +++ b/website/thaliawebsite/views.py
  @@ -31,6 +31,7 @@
   
       def get_context_data(self, **kwargs) -> dict:
           context = super().get_context_data(**kwargs)
  +        print(kwargs)
           page = context["page_obj"].number
           paginator = context["paginator"]
   
  @@ -48,9 +49,17 @@
   
           page_range = range(page_range_start, page_range_stop)
   
  +        querydict = self.request.GET.copy()
  +
  +        if "page" in querydict:
  +            del querydict["page"]
  +
           context.update(
               {
                   "page_range": page_range,
  +                "base_url": f"{self.request.path}?{querydict.urlencode()}&"
  +                if querydict
  +                else f"{self.request.path}?",
               }
           )
  
verification_info: {"golden_diff": "diff --git a/website/thaliawebsite/views.py b/website/thaliawebsite/views.py\n--- a/website/thaliawebsite/views.py\n+++ b/website/thaliawebsite/views.py\n@@ -31,6 +31,7 @@\n \n     def get_context_data(self, **kwargs) -> dict:\n         context = super().get_context_data(**kwargs)\n+        print(kwargs)\n         page = context[\"page_obj\"].number\n         paginator = context[\"paginator\"]\n \n@@ -48,9 +49,17 @@\n \n         page_range = range(page_range_start, page_range_stop)\n \n+        querydict = self.request.GET.copy()\n+\n+        if \"page\" in querydict:\n+            del querydict[\"page\"]\n+\n         context.update(\n             {\n                 \"page_range\": page_range,\n+                \"base_url\": f\"{self.request.path}?{querydict.urlencode()}&\"\n+                if querydict\n+                else f\"{self.request.path}?\",\n             }\n         )\n", "issue": "Albums pagination doesn't maintain search terms\n### Describe the bug\r\nIf you open https://thalia.nu/members/photos/?keywords=borrel#photos-albums, then go to the second page using the pagination buttons, the search term is dropped.\r\n\r\n### Expected behaviour\r\n<!-- A clear and concise description of what you expected to happen. -->\r\nThe search term remains\r\n\r\n### Additional context\r\n<!-- Add any other context about the problem here. -->\r\nCould be since we introduced the shared paginated view template? So it's quite likely this occurs for other paginated filterable/searchable views as well.\n", "before_files": [{"content": "\"\"\"General views for the website.\"\"\"\n\nfrom django.contrib.admin.views.decorators import staff_member_required\nfrom django.contrib.auth.views import LoginView, PasswordResetView\nfrom django.core.exceptions import PermissionDenied\nfrom django.http import HttpResponse, HttpResponseForbidden\nfrom django.shortcuts import redirect\nfrom django.utils.decorators import method_decorator\nfrom django.views.generic import ListView, TemplateView\nfrom django.views.generic.base import View\n\nfrom django_ratelimit.decorators import ratelimit\n\n\nclass IndexView(TemplateView):\n    template_name = \"index.html\"\n\n\n@method_decorator(staff_member_required, \"dispatch\")\nclass TestCrashView(View):\n    \"\"\"Test view to intentionally crash to test the error handling.\"\"\"\n\n    def dispatch(self, request, *args, **kwargs) -> HttpResponse:\n        if not request.user.is_superuser:\n            return HttpResponseForbidden(\"This is not for you\")\n        raise Exception(\"Test exception\")\n\n\nclass PagedView(ListView):\n    \"\"\"A ListView with automatic pagination.\"\"\"\n\n    def get_context_data(self, **kwargs) -> dict:\n        context = super().get_context_data(**kwargs)\n        page = context[\"page_obj\"].number\n        paginator = context[\"paginator\"]\n\n        # Show the two pages before and after the current page\n        page_range_start = max(1, page - 2)\n        page_range_stop = min(page + 3, paginator.num_pages + 1)\n\n        # Add extra pages if we show less than 5 pages\n        page_range_start = min(page_range_start, page_range_stop - 5)\n        page_range_start = max(1, page_range_start)\n\n        # Add extra pages if we still show less than 5 pages\n        page_range_stop = max(page_range_stop, page_range_start + 5)\n        page_range_stop = min(page_range_stop, paginator.num_pages + 1)\n\n        page_range = range(page_range_start, page_range_stop)\n\n        context.update(\n            {\n                \"page_range\": page_range,\n            }\n        )\n\n        return context\n\n\nclass RateLimitedPasswordResetView(PasswordResetView):\n    @method_decorator(ratelimit(key=\"ip\", rate=\"5/h\"))\n    def post(self, request, *args, **kwargs):\n        return super().post(request, *args, **kwargs)\n\n\nclass RateLimitedLoginView(LoginView):\n    @method_decorator(ratelimit(key=\"ip\", rate=\"30/h\"))\n    @method_decorator(ratelimit(key=\"post:username\", rate=\"30/h\"))\n    def post(self, request, *args, **kwargs):\n        return super().post(request, *args, **kwargs)\n\n\ndef rate_limited_view(request, *args, **kwargs):\n    return HttpResponse(\"You are rate limited\", status=429)\n\n\ndef admin_unauthorized_view(request):\n    if not request.member:\n        url = \"/user/login\"\n        args = request.META.get(\"QUERY_STRING\", \"\")\n        if args:\n            url = f\"{url}?{args}\"\n        return redirect(url)\n    elif not request.member.is_staff and not request.member.is_superuser:\n        raise PermissionDenied(\"You are not allowed to access the administration page.\")\n    else:\n        return redirect(request.GET.get(\"next\", \"/\"))\n", "path": "website/thaliawebsite/views.py"}], "after_files": [{"content": "\"\"\"General views for the website.\"\"\"\n\nfrom django.contrib.admin.views.decorators import staff_member_required\nfrom django.contrib.auth.views import LoginView, PasswordResetView\nfrom django.core.exceptions import PermissionDenied\nfrom django.http import HttpResponse, HttpResponseForbidden\nfrom django.shortcuts import redirect\nfrom django.utils.decorators import method_decorator\nfrom django.views.generic import ListView, TemplateView\nfrom django.views.generic.base import View\n\nfrom django_ratelimit.decorators import ratelimit\n\n\nclass IndexView(TemplateView):\n    template_name = \"index.html\"\n\n\n@method_decorator(staff_member_required, \"dispatch\")\nclass TestCrashView(View):\n    \"\"\"Test view to intentionally crash to test the error handling.\"\"\"\n\n    def dispatch(self, request, *args, **kwargs) -> HttpResponse:\n        if not request.user.is_superuser:\n            return HttpResponseForbidden(\"This is not for you\")\n        raise Exception(\"Test exception\")\n\n\nclass PagedView(ListView):\n    \"\"\"A ListView with automatic pagination.\"\"\"\n\n    def get_context_data(self, **kwargs) -> dict:\n        context = super().get_context_data(**kwargs)\n        print(kwargs)\n        page = context[\"page_obj\"].number\n        paginator = context[\"paginator\"]\n\n        # Show the two pages before and after the current page\n        page_range_start = max(1, page - 2)\n        page_range_stop = min(page + 3, paginator.num_pages + 1)\n\n        # Add extra pages if we show less than 5 pages\n        page_range_start = min(page_range_start, page_range_stop - 5)\n        page_range_start = max(1, page_range_start)\n\n        # Add extra pages if we still show less than 5 pages\n        page_range_stop = max(page_range_stop, page_range_start + 5)\n        page_range_stop = min(page_range_stop, paginator.num_pages + 1)\n\n        page_range = range(page_range_start, page_range_stop)\n\n        querydict = self.request.GET.copy()\n\n        if \"page\" in querydict:\n            del querydict[\"page\"]\n\n        context.update(\n            {\n                \"page_range\": page_range,\n                \"base_url\": f\"{self.request.path}?{querydict.urlencode()}&\"\n                if querydict\n                else f\"{self.request.path}?\",\n            }\n        )\n\n        return context\n\n\nclass RateLimitedPasswordResetView(PasswordResetView):\n    @method_decorator(ratelimit(key=\"ip\", rate=\"5/h\"))\n    def post(self, request, *args, **kwargs):\n        return super().post(request, *args, **kwargs)\n\n\nclass RateLimitedLoginView(LoginView):\n    @method_decorator(ratelimit(key=\"ip\", rate=\"30/h\"))\n    @method_decorator(ratelimit(key=\"post:username\", rate=\"30/h\"))\n    def post(self, request, *args, **kwargs):\n        return super().post(request, *args, **kwargs)\n\n\ndef rate_limited_view(request, *args, **kwargs):\n    return HttpResponse(\"You are rate limited\", status=429)\n\n\ndef admin_unauthorized_view(request):\n    if not request.member:\n        url = \"/user/login\"\n        args = request.META.get(\"QUERY_STRING\", \"\")\n        if args:\n            url = f\"{url}?{args}\"\n        return redirect(url)\n    elif not request.member.is_staff and not request.member.is_superuser:\n        raise PermissionDenied(\"You are not allowed to access the administration page.\")\n    else:\n        return redirect(request.GET.get(\"next\", \"/\"))\n", "path": "website/thaliawebsite/views.py"}]}