Fixed #33316 -- Added pagination to admin history view.

This commit is contained in:
mgaligniana 2021-12-14 03:03:36 -03:00 committed by Mariusz Felisiak
parent ff0b81b56b
commit ac5cc6cf01
6 changed files with 95 additions and 6 deletions

View File

@ -1927,6 +1927,7 @@ class ModelAdmin(BaseModelAdmin):
def history_view(self, request, object_id, extra_context=None):
"The 'history' admin view for this model."
from django.contrib.admin.models import LogEntry
from django.contrib.admin.views.main import PAGE_VAR
# First check if the user can see this history.
model = self.model
@ -1945,11 +1946,19 @@ class ModelAdmin(BaseModelAdmin):
content_type=get_content_type_for_model(model)
).select_related().order_by('action_time')
paginator = self.get_paginator(request, action_list, 100)
page_number = request.GET.get(PAGE_VAR, 1)
page_obj = paginator.get_page(page_number)
page_range = paginator.get_elided_page_range(page_obj.number)
context = {
**self.admin_site.each_context(request),
'title': _('Change history: %s') % obj,
'subtitle': None,
'action_list': action_list,
'action_list': page_obj,
'page_range': page_range,
'page_var': PAGE_VAR,
'pagination_required': paginator.count > 100,
'module_name': str(capfirst(opts.verbose_name_plural)),
'object': obj,
'opts': opts,

View File

@ -774,14 +774,21 @@ a.deletelink:focus, a.deletelink:hover {
/* OBJECT HISTORY */
table#change-history {
#change-history table {
width: 100%;
}
table#change-history tbody th {
#change-history table tbody th {
width: 16em;
}
#change-history .paginator {
color: var(--body-quiet-color);
border-bottom: 1px solid var(--hairline-color);
background: var(--body-bg);
overflow: hidden;
}
/* PAGE STRUCTURE */
#container {

View File

@ -13,10 +13,10 @@
{% block content %}
<div id="content-main">
<div class="module">
<div id="change-history" class="module">
{% if action_list %}
<table id="change-history">
<table>
<thead>
<tr>
<th scope="col">{% translate 'Date/time' %}</th>
@ -34,6 +34,20 @@
{% endfor %}
</tbody>
</table>
<p class="paginator">
{% if pagination_required %}
{% for i in page_range %}
{% if i == action_list.paginator.ELLIPSIS %}
{{ action_list.paginator.ELLIPSIS }}
{% elif i == action_list.number %}
<span class="this-page">{{ i }}</span>
{% else %}
<a href="?{{ page_var }}={{ i }}" {% if i == action_list.paginator.num_pages %} class="end" {% endif %}>{{ i }}</a>
{% endif %}
{% endfor %}
{% endif %}
{{ action_list.paginator.count }} {% if action_list.paginator.count == 1 %}{% translate "entry" %}{% else %}{% translate "entries" %}{% endif %}
</p>
{% else %}
<p>{% translate 'This object doesnt have a change history. It probably wasnt added via this admin site.' %}</p>
{% endif %}

View File

@ -2016,6 +2016,10 @@ Other methods
Django view for the page that shows the modification history for a given
model instance.
.. versionchanged:: 4.1
Pagination was added.
Unlike the hook-type ``ModelAdmin`` methods detailed in the previous section,
these five methods are in reality designed to be invoked as Django views from
the admin application URL dispatching handler to render the pages that deal

View File

@ -58,6 +58,9 @@ Minor features
subclasses can now control the query string value separator when filtering
for multiple values using the ``__in`` lookup.
* The admin :meth:`history view <django.contrib.admin.ModelAdmin.history_view>`
is now paginated.
:mod:`django.contrib.admindocs`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -1,5 +1,8 @@
from django.contrib.admin.models import LogEntry
from django.contrib.admin.models import CHANGE, LogEntry
from django.contrib.admin.tests import AdminSeleniumTestCase
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.core.paginator import Paginator
from django.test import TestCase, override_settings
from django.urls import reverse
@ -43,3 +46,52 @@ class AdminHistoryViewTests(TestCase):
'nolabel_form_field and not_a_form_field. '
'Changed City verbose_name for city “%s”.' % city
)
@override_settings(ROOT_URLCONF='admin_views.urls')
class SeleniumTests(AdminSeleniumTestCase):
available_apps = ['admin_views'] + AdminSeleniumTestCase.available_apps
def setUp(self):
self.superuser = User.objects.create_superuser(
username='super', password='secret', email='super@example.com',
)
content_type_pk = ContentType.objects.get_for_model(User).pk
for i in range(1, 1101):
LogEntry.objects.log_action(
self.superuser.pk,
content_type_pk,
self.superuser.pk,
repr(self.superuser),
CHANGE,
change_message=f'Changed something {i}',
)
self.admin_login(
username='super', password='secret', login_url=reverse('admin:index'),
)
def test_pagination(self):
from selenium.webdriver.common.by import By
user_history_url = reverse('admin:auth_user_history', args=(self.superuser.pk,))
self.selenium.get(self.live_server_url + user_history_url)
paginator = self.selenium.find_element(By.CSS_SELECTOR, '.paginator')
self.assertTrue(paginator.is_displayed())
self.assertIn('%s entries' % LogEntry.objects.count(), paginator.text)
self.assertIn(str(Paginator.ELLIPSIS), paginator.text)
# The current page.
current_page_link = self.selenium.find_element(By.CSS_SELECTOR, 'span.this-page')
self.assertEqual(current_page_link.text, '1')
# The last page.
last_page_link = self.selenium.find_element(By.CSS_SELECTOR, '.end')
self.assertTrue(last_page_link.text, '20')
# Select the second page.
pages = paginator.find_elements(By.TAG_NAME, 'a')
second_page_link = pages[0]
self.assertEqual(second_page_link.text, '2')
second_page_link.click()
self.assertIn('?p=2', self.selenium.current_url)
rows = self.selenium.find_elements(By.CSS_SELECTOR, '#change-history tbody tr')
self.assertIn('Changed something 101', rows[0].text)
self.assertIn('Changed something 200', rows[-1].text)