prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Build List Screen Performance Issue
  While working on #5464, I discovered a performance issue on the [build list screen](http://readthedocs.org/projects/requests/builds/).
  
  There appears to be a couple duplicated queries in the build list screen. One is to get the project (probably from `Build.get_absolute_url`) for the build and the other gets the version (probably from `build_list_detailed.html`). This results in O(n) SQL queries where n is the number of builds displayed. It should be possible to get the project and version for each build using `select_related`.
  
  <img width="1155" alt="Screen Shot 2019-03-15 at 11 00 13 AM" src="https://user-images.githubusercontent.com/185043/54452149-a0d76e80-4711-11e9-82f4-763418863f94.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: `readthedocs/builds/views.py`
  Content:
  ```
  1 # -*- coding: utf-8 -*-
  2 
  3 """Views for builds app."""
  4 
  5 import logging
  6 import textwrap
  7 
  8 from django.contrib import messages
  9 from django.contrib.auth.decorators import login_required
  10 from django.http import (
  11     HttpResponseForbidden,
  12     HttpResponsePermanentRedirect,
  13     HttpResponseRedirect,
  14 )
  15 from django.shortcuts import get_object_or_404
  16 from django.urls import reverse
  17 from django.utils.decorators import method_decorator
  18 from django.views.generic import DetailView, ListView
  19 from requests.utils import quote
  20 from urllib.parse import urlparse
  21 
  22 from readthedocs.doc_builder.exceptions import BuildEnvironmentError
  23 from readthedocs.builds.models import Build, Version
  24 from readthedocs.core.permissions import AdminPermission
  25 from readthedocs.core.utils import trigger_build
  26 from readthedocs.projects.models import Project
  27 
  28 
  29 log = logging.getLogger(__name__)
  30 
  31 
  32 class BuildBase:
  33     model = Build
  34 
  35     def get_queryset(self):
  36         self.project_slug = self.kwargs.get('project_slug', None)
  37         self.project = get_object_or_404(
  38             Project.objects.protected(self.request.user),
  39             slug=self.project_slug,
  40         )
  41         queryset = Build.objects.public(
  42             user=self.request.user,
  43             project=self.project,
  44         )
  45 
  46         return queryset
  47 
  48 
  49 class BuildTriggerMixin:
  50 
  51     @method_decorator(login_required)
  52     def post(self, request, project_slug):
  53         project = get_object_or_404(Project, slug=project_slug)
  54 
  55         if not AdminPermission.is_admin(request.user, project):
  56             return HttpResponseForbidden()
  57 
  58         version_slug = request.POST.get('version_slug')
  59         version = get_object_or_404(
  60             Version,
  61             project=project,
  62             slug=version_slug,
  63         )
  64 
  65         update_docs_task, build = trigger_build(
  66             project=project,
  67             version=version,
  68         )
  69         if (update_docs_task, build) == (None, None):
  70             # Build was skipped
  71             messages.add_message(
  72                 request,
  73                 messages.WARNING,
  74                 "This project is currently disabled and can't trigger new builds.",
  75             )
  76             return HttpResponseRedirect(
  77                 reverse('builds_project_list', args=[project.slug]),
  78             )
  79 
  80         return HttpResponseRedirect(
  81             reverse('builds_detail', args=[project.slug, build.pk]),
  82         )
  83 
  84 
  85 class BuildList(BuildBase, BuildTriggerMixin, ListView):
  86 
  87     def get_context_data(self, **kwargs):
  88         context = super().get_context_data(**kwargs)
  89 
  90         active_builds = self.get_queryset().exclude(
  91             state='finished',
  92         ).values('id')
  93 
  94         context['project'] = self.project
  95         context['active_builds'] = active_builds
  96         context['versions'] = Version.objects.public(
  97             user=self.request.user,
  98             project=self.project,
  99         )
  100         context['build_qs'] = self.get_queryset()
  101 
  102         return context
  103 
  104 
  105 class BuildDetail(BuildBase, DetailView):
  106     pk_url_kwarg = 'build_pk'
  107 
  108     def get_context_data(self, **kwargs):
  109         context = super().get_context_data(**kwargs)
  110         context['project'] = self.project
  111 
  112         build = self.get_object()
  113         if build.error != BuildEnvironmentError.GENERIC_WITH_BUILD_ID.format(build_id=build.pk):
  114             # Do not suggest to open an issue if the error is not generic
  115             return context
  116 
  117         scheme = (
  118             'https://github.com/rtfd/readthedocs.org/issues/new'
  119             '?title={title}{build_id}'
  120             '&body={body}'
  121         )
  122 
  123         # TODO: we could use ``.github/ISSUE_TEMPLATE.md`` here, but we would
  124         # need to add some variables to it which could impact in the UX when
  125         # filling an issue from the web
  126         body = """
  127         ## Details:
  128 
  129         * Project URL: https://readthedocs.org/projects/{project_slug}/
  130         * Build URL(if applicable): https://readthedocs.org{build_path}
  131         * Read the Docs username(if applicable): {username}
  132 
  133         ## Expected Result
  134 
  135         *A description of what you wanted to happen*
  136 
  137         ## Actual Result
  138 
  139         *A description of what actually happened*""".format(
  140             project_slug=self.project,
  141             build_path=self.request.path,
  142             username=self.request.user,
  143         )
  144 
  145         scheme_dict = {
  146             'title': quote('Build error with build id #'),
  147             'build_id': context['build'].id,
  148             'body': quote(textwrap.dedent(body)),
  149         }
  150 
  151         issue_url = scheme.format(**scheme_dict)
  152         issue_url = urlparse(issue_url).geturl()
  153         context['issue_url'] = issue_url
  154         return context
  155 
  156 
  157 # Old build view redirects
  158 
  159 
  160 def builds_redirect_list(request, project_slug):  # pylint: disable=unused-argument
  161     return HttpResponsePermanentRedirect(
  162         reverse('builds_project_list', args=[project_slug]),
  163     )
  164 
  165 
  166 def builds_redirect_detail(request, project_slug, pk):  # pylint: disable=unused-argument
  167     return HttpResponsePermanentRedirect(
  168         reverse('builds_detail', args=[project_slug, pk]),
  169     )
  170
  ```
  --- 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/readthedocs/builds/views.py b/readthedocs/builds/views.py
  --- a/readthedocs/builds/views.py
  +++ b/readthedocs/builds/views.py
  @@ -41,7 +41,7 @@
           queryset = Build.objects.public(
               user=self.request.user,
               project=self.project,
  -        )
  +        ).select_related('project', 'version')
   
           return queryset
  
verification_info: {"golden_diff": "diff --git a/readthedocs/builds/views.py b/readthedocs/builds/views.py\n--- a/readthedocs/builds/views.py\n+++ b/readthedocs/builds/views.py\n@@ -41,7 +41,7 @@\n         queryset = Build.objects.public(\n             user=self.request.user,\n             project=self.project,\n-        )\n+        ).select_related('project', 'version')\n \n         return queryset\n", "issue": "Build List Screen Performance Issue\nWhile working on #5464, I discovered a performance issue on the [build list screen](http://readthedocs.org/projects/requests/builds/).\r\n\r\nThere appears to be a couple duplicated queries in the build list screen. One is to get the project (probably from `Build.get_absolute_url`) for the build and the other gets the version (probably from `build_list_detailed.html`). This results in O(n) SQL queries where n is the number of builds displayed. It should be possible to get the project and version for each build using `select_related`.\r\n\r\n<img width=\"1155\" alt=\"Screen Shot 2019-03-15 at 11 00 13 AM\" src=\"https://user-images.githubusercontent.com/185043/54452149-a0d76e80-4711-11e9-82f4-763418863f94.png\">\r\n\r\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\n\"\"\"Views for builds app.\"\"\"\n\nimport logging\nimport textwrap\n\nfrom django.contrib import messages\nfrom django.contrib.auth.decorators import login_required\nfrom django.http import (\n    HttpResponseForbidden,\n    HttpResponsePermanentRedirect,\n    HttpResponseRedirect,\n)\nfrom django.shortcuts import get_object_or_404\nfrom django.urls import reverse\nfrom django.utils.decorators import method_decorator\nfrom django.views.generic import DetailView, ListView\nfrom requests.utils import quote\nfrom urllib.parse import urlparse\n\nfrom readthedocs.doc_builder.exceptions import BuildEnvironmentError\nfrom readthedocs.builds.models import Build, Version\nfrom readthedocs.core.permissions import AdminPermission\nfrom readthedocs.core.utils import trigger_build\nfrom readthedocs.projects.models import Project\n\n\nlog = logging.getLogger(__name__)\n\n\nclass BuildBase:\n    model = Build\n\n    def get_queryset(self):\n        self.project_slug = self.kwargs.get('project_slug', None)\n        self.project = get_object_or_404(\n            Project.objects.protected(self.request.user),\n            slug=self.project_slug,\n        )\n        queryset = Build.objects.public(\n            user=self.request.user,\n            project=self.project,\n        )\n\n        return queryset\n\n\nclass BuildTriggerMixin:\n\n    @method_decorator(login_required)\n    def post(self, request, project_slug):\n        project = get_object_or_404(Project, slug=project_slug)\n\n        if not AdminPermission.is_admin(request.user, project):\n            return HttpResponseForbidden()\n\n        version_slug = request.POST.get('version_slug')\n        version = get_object_or_404(\n            Version,\n            project=project,\n            slug=version_slug,\n        )\n\n        update_docs_task, build = trigger_build(\n            project=project,\n            version=version,\n        )\n        if (update_docs_task, build) == (None, None):\n            # Build was skipped\n            messages.add_message(\n                request,\n                messages.WARNING,\n                \"This project is currently disabled and can't trigger new builds.\",\n            )\n            return HttpResponseRedirect(\n                reverse('builds_project_list', args=[project.slug]),\n            )\n\n        return HttpResponseRedirect(\n            reverse('builds_detail', args=[project.slug, build.pk]),\n        )\n\n\nclass BuildList(BuildBase, BuildTriggerMixin, ListView):\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n\n        active_builds = self.get_queryset().exclude(\n            state='finished',\n        ).values('id')\n\n        context['project'] = self.project\n        context['active_builds'] = active_builds\n        context['versions'] = Version.objects.public(\n            user=self.request.user,\n            project=self.project,\n        )\n        context['build_qs'] = self.get_queryset()\n\n        return context\n\n\nclass BuildDetail(BuildBase, DetailView):\n    pk_url_kwarg = 'build_pk'\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n        context['project'] = self.project\n\n        build = self.get_object()\n        if build.error != BuildEnvironmentError.GENERIC_WITH_BUILD_ID.format(build_id=build.pk):\n            # Do not suggest to open an issue if the error is not generic\n            return context\n\n        scheme = (\n            'https://github.com/rtfd/readthedocs.org/issues/new'\n            '?title={title}{build_id}'\n            '&body={body}'\n        )\n\n        # TODO: we could use ``.github/ISSUE_TEMPLATE.md`` here, but we would\n        # need to add some variables to it which could impact in the UX when\n        # filling an issue from the web\n        body = \"\"\"\n        ## Details:\n\n        * Project URL: https://readthedocs.org/projects/{project_slug}/\n        * Build URL(if applicable): https://readthedocs.org{build_path}\n        * Read the Docs username(if applicable): {username}\n\n        ## Expected Result\n\n        *A description of what you wanted to happen*\n\n        ## Actual Result\n\n        *A description of what actually happened*\"\"\".format(\n            project_slug=self.project,\n            build_path=self.request.path,\n            username=self.request.user,\n        )\n\n        scheme_dict = {\n            'title': quote('Build error with build id #'),\n            'build_id': context['build'].id,\n            'body': quote(textwrap.dedent(body)),\n        }\n\n        issue_url = scheme.format(**scheme_dict)\n        issue_url = urlparse(issue_url).geturl()\n        context['issue_url'] = issue_url\n        return context\n\n\n# Old build view redirects\n\n\ndef builds_redirect_list(request, project_slug):  # pylint: disable=unused-argument\n    return HttpResponsePermanentRedirect(\n        reverse('builds_project_list', args=[project_slug]),\n    )\n\n\ndef builds_redirect_detail(request, project_slug, pk):  # pylint: disable=unused-argument\n    return HttpResponsePermanentRedirect(\n        reverse('builds_detail', args=[project_slug, pk]),\n    )\n", "path": "readthedocs/builds/views.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\n\"\"\"Views for builds app.\"\"\"\n\nimport logging\nimport textwrap\n\nfrom django.contrib import messages\nfrom django.contrib.auth.decorators import login_required\nfrom django.http import (\n    HttpResponseForbidden,\n    HttpResponsePermanentRedirect,\n    HttpResponseRedirect,\n)\nfrom django.shortcuts import get_object_or_404\nfrom django.urls import reverse\nfrom django.utils.decorators import method_decorator\nfrom django.views.generic import DetailView, ListView\nfrom requests.utils import quote\nfrom urllib.parse import urlparse\n\nfrom readthedocs.doc_builder.exceptions import BuildEnvironmentError\nfrom readthedocs.builds.models import Build, Version\nfrom readthedocs.core.permissions import AdminPermission\nfrom readthedocs.core.utils import trigger_build\nfrom readthedocs.projects.models import Project\n\n\nlog = logging.getLogger(__name__)\n\n\nclass BuildBase:\n    model = Build\n\n    def get_queryset(self):\n        self.project_slug = self.kwargs.get('project_slug', None)\n        self.project = get_object_or_404(\n            Project.objects.protected(self.request.user),\n            slug=self.project_slug,\n        )\n        queryset = Build.objects.public(\n            user=self.request.user,\n            project=self.project,\n        ).select_related('project', 'version')\n\n        return queryset\n\n\nclass BuildTriggerMixin:\n\n    @method_decorator(login_required)\n    def post(self, request, project_slug):\n        project = get_object_or_404(Project, slug=project_slug)\n\n        if not AdminPermission.is_admin(request.user, project):\n            return HttpResponseForbidden()\n\n        version_slug = request.POST.get('version_slug')\n        version = get_object_or_404(\n            Version,\n            project=project,\n            slug=version_slug,\n        )\n\n        update_docs_task, build = trigger_build(\n            project=project,\n            version=version,\n        )\n        if (update_docs_task, build) == (None, None):\n            # Build was skipped\n            messages.add_message(\n                request,\n                messages.WARNING,\n                \"This project is currently disabled and can't trigger new builds.\",\n            )\n            return HttpResponseRedirect(\n                reverse('builds_project_list', args=[project.slug]),\n            )\n\n        return HttpResponseRedirect(\n            reverse('builds_detail', args=[project.slug, build.pk]),\n        )\n\n\nclass BuildList(BuildBase, BuildTriggerMixin, ListView):\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n\n        active_builds = self.get_queryset().exclude(\n            state='finished',\n        ).values('id')\n\n        context['project'] = self.project\n        context['active_builds'] = active_builds\n        context['versions'] = Version.objects.public(\n            user=self.request.user,\n            project=self.project,\n        )\n        context['build_qs'] = self.get_queryset()\n\n        return context\n\n\nclass BuildDetail(BuildBase, DetailView):\n    pk_url_kwarg = 'build_pk'\n\n    def get_context_data(self, **kwargs):\n        context = super().get_context_data(**kwargs)\n        context['project'] = self.project\n\n        build = self.get_object()\n        if build.error != BuildEnvironmentError.GENERIC_WITH_BUILD_ID.format(build_id=build.pk):\n            # Do not suggest to open an issue if the error is not generic\n            return context\n\n        scheme = (\n            'https://github.com/rtfd/readthedocs.org/issues/new'\n            '?title={title}{build_id}'\n            '&body={body}'\n        )\n\n        # TODO: we could use ``.github/ISSUE_TEMPLATE.md`` here, but we would\n        # need to add some variables to it which could impact in the UX when\n        # filling an issue from the web\n        body = \"\"\"\n        ## Details:\n\n        * Project URL: https://readthedocs.org/projects/{project_slug}/\n        * Build URL(if applicable): https://readthedocs.org{build_path}\n        * Read the Docs username(if applicable): {username}\n\n        ## Expected Result\n\n        *A description of what you wanted to happen*\n\n        ## Actual Result\n\n        *A description of what actually happened*\"\"\".format(\n            project_slug=self.project,\n            build_path=self.request.path,\n            username=self.request.user,\n        )\n\n        scheme_dict = {\n            'title': quote('Build error with build id #'),\n            'build_id': context['build'].id,\n            'body': quote(textwrap.dedent(body)),\n        }\n\n        issue_url = scheme.format(**scheme_dict)\n        issue_url = urlparse(issue_url).geturl()\n        context['issue_url'] = issue_url\n        return context\n\n\n# Old build view redirects\n\n\ndef builds_redirect_list(request, project_slug):  # pylint: disable=unused-argument\n    return HttpResponsePermanentRedirect(\n        reverse('builds_project_list', args=[project_slug]),\n    )\n\n\ndef builds_redirect_detail(request, project_slug, pk):  # pylint: disable=unused-argument\n    return HttpResponsePermanentRedirect(\n        reverse('builds_detail', args=[project_slug, pk]),\n    )\n", "path": "readthedocs/builds/views.py"}]}