docs: def old_changelist_view(self, request, extra_context=None):
          "The 'change list' admin view for this model."
          from django.contrib.admin.views.main import ERROR_FLAG
          from django.core.exceptions import PermissionDenied
          from django.utils.encoding import force_text
          from django.utils.translation import ungettext
          opts = self.model._meta
          app_label = opts.app_label
          if not self.has_change_permission(request, None):
              raise PermissionDenied
  
          # Check actions to see if any are available on this changelist
          actions = self.get_actions(request)
  
          # Remove action checkboxes if there aren't any actions available.
          list_display = list(self.list_display)
          if not actions:
              try:
                  list_display.remove('action_checkbox')
              except ValueError:
                  pass
  
          try:
              if django.VERSION[0] == 1 and django.VERSION[1] < 4:
                  params = (
                      request, self.model, list_display,
                      self.list_display_links, self.list_filter, self.date_hierarchy,
                      self.search_fields, self.list_select_related,
                      self.list_per_page, self.list_editable, self)
              elif django.VERSION[0] == 1 or (django.VERSION[0] == 2 and django.VERSION[1] < 1):
                  params = (
                      request, self.model, list_display,
                      self.list_display_links, self.list_filter, self.date_hierarchy,
                      self.search_fields, self.list_select_related,
                      self.list_per_page, self.list_max_show_all,
                      self.list_editable, self)
              else:
                  params = (
                      request, self.model, list_display,
                      self.list_display_links, self.list_filter, self.date_hierarchy,
                      self.search_fields, self.list_select_related,
                      self.list_per_page, self.list_max_show_all,
                      self.list_editable, self, self.sortable_by)
              cl = TreeChangeList(*params)
          except IncorrectLookupParameters:
              # Wacky lookup parameters were given, so redirect to the main
              # changelist page, without parameters, and pass an 'invalid=1'
              # parameter via the query string. If wacky parameters were given and
              # the 'invalid=1' parameter was already in the query string, something
              # is screwed up with the database, so display an error page.
              if ERROR_FLAG in list(request.GET.keys()):
                  return render_to_response(
                      'admin/invalid_setup.html', {'title': _('Database error')})
              return HttpResponseRedirect(request.path + '?' + ERROR_FLAG + '=1')
  
          # If the request was POSTed, this might be a bulk action or a bulk edit.
          # Try to look up an action first, but if this isn't an action the POST
          # will fall through to the bulk edit check, below.
          if actions and request.method == 'POST':
              response = self.response_action(request, queryset=cl.get_queryset())
              if response:
                  return response
  
          # If we're allowing changelist editing, we need to construct a formset
          # for the changelist given all the fields to be edited. Then we'll
          # use the formset to validate/process POSTed data.
          formset = cl.formset = None
  
          # Handle POSTed bulk-edit data.
          if request.method == "POST" and self.list_editable:
              FormSet = self.get_changelist_formset(request)
              formset = cl.formset = FormSet(
                  request.POST, request.FILES, queryset=cl.result_list
              )
              if formset.is_valid():
                  changecount = 0
                  for form in formset.forms:
                      if form.has_changed():
                          obj = self.save_form(request, form, change=True)
                          self.save_model(request, obj, form, change=True)
                          form.save_m2m()
                          change_msg = self.construct_change_message(request, form, None)
                          self.log_change(request, obj, change_msg)
                          changecount += 1
  
                  if changecount:
                      if changecount == 1:
                          name = force_text(opts.verbose_name)
                      else:
                          name = force_text(opts.verbose_name_plural)
                      msg = ungettext(
                          "%(count)s %(name)s was changed successfully.",
                          "%(count)s %(name)s were changed successfully.",
                          changecount) % {'count': changecount,
                                          'name': name,
                                          'obj': force_text(obj)}
                      self.message_user(request, msg)
  
                  return HttpResponseRedirect(request.get_full_path())
  
          # Handle GET -- construct a formset for display.
          elif self.list_editable:
              FormSet = self.get_changelist_formset(request)
              formset = cl.formset = FormSet(queryset=cl.result_list)
  
          # Build the list of media to be used by the formset.
          if formset:
              media = self.media + formset.media
          else:
              media = self.media
  
          # Build the action form and populate it with available actions.
          if actions:
              action_form = self.action_form(auto_id=None)
              action_form.fields['action'].choices = self.get_action_choices(request)
          else:
              action_form = None
  
          context = {
              'title': cl.title,
              'is_popup': cl.is_popup,
              'cl': cl,
              'media': media,
              'has_add_permission': self.has_add_permission(request),
              'app_label': app_label,
              'action_form': action_form,
              'actions_on_top': self.actions_on_top,
              'actions_on_bottom': self.actions_on_bottom,
          }
          if django.VERSION[0] == 1 and django.VERSION[1] < 4:
              context['root_path'] = self.admin_site.root_path
          elif django.VERSION[0] == 1 or (django.VERSION[0] == 2 and django.VERSION[1] < 1):
              selection_note_all = ungettext('%(total_count)s selected', 'All %(total_count)s selected', cl.result_count)
  
              context.update({
                  'module_name': force_text(opts.verbose_name_plural),
                  'selection_note': _('0 of %(cnt)s selected') % {'cnt': len(cl.result_list)},
                  'selection_note_all': selection_note_all % {'total_count': cl.result_count},
              })
          else:
              context['opts'] = self.model._meta
  
          context.update(extra_context or {})
          return render_to_response(self.change_list_template or [
              'admin/%s/%s/change_list.html' % (app_label, opts.object_name.lower()),
              'admin/%s/change_list.html' % app_label,
              'admin/change_list.html'
          ], context=context)