diff options
author | django-bot <ops@djangoproject.com> | 2022-02-03 20:24:19 +0100 |
---|---|---|
committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2022-02-07 20:37:05 +0100 |
commit | 9c19aff7c7561e3a82978a272ecdaad40dda5c00 (patch) | |
tree | f0506b668a013d0063e5fba3dbf4863b466713ba /tests/admin_changelist | |
parent | f68fa8b45dfac545cfc4111d4e52804c86db68d3 (diff) | |
download | django-9c19aff7c7561e3a82978a272ecdaad40dda5c00.tar.gz |
Refs #33476 -- Reformatted code with Black.
Diffstat (limited to 'tests/admin_changelist')
-rw-r--r-- | tests/admin_changelist/admin.py | 92 | ||||
-rw-r--r-- | tests/admin_changelist/models.py | 12 | ||||
-rw-r--r-- | tests/admin_changelist/test_date_hierarchy.py | 71 | ||||
-rw-r--r-- | tests/admin_changelist/tests.py | 1200 | ||||
-rw-r--r-- | tests/admin_changelist/urls.py | 2 |
5 files changed, 757 insertions, 620 deletions
diff --git a/tests/admin_changelist/admin.py b/tests/admin_changelist/admin.py index 929539ea88..67187f5b79 100644 --- a/tests/admin_changelist/admin.py +++ b/tests/admin_changelist/admin.py @@ -12,12 +12,14 @@ site.register(User, UserAdmin) class CustomPaginator(Paginator): def __init__(self, queryset, page_size, orphans=0, allow_empty_first_page=True): - super().__init__(queryset, 5, orphans=2, allow_empty_first_page=allow_empty_first_page) + super().__init__( + queryset, 5, orphans=2, allow_empty_first_page=allow_empty_first_page + ) class EventAdmin(admin.ModelAdmin): - date_hierarchy = 'date' - list_display = ['event_date_func'] + date_hierarchy = "date" + list_display = ["event_date_func"] @admin.display def event_date_func(self, event): @@ -31,21 +33,21 @@ site.register(Event, EventAdmin) class ParentAdmin(admin.ModelAdmin): - list_filter = ['child__name'] - search_fields = ['child__name'] - list_select_related = ['child'] + list_filter = ["child__name"] + search_fields = ["child__name"] + list_select_related = ["child"] class ParentAdminTwoSearchFields(admin.ModelAdmin): - list_filter = ['child__name'] - search_fields = ['child__name', 'child__age'] - list_select_related = ['child'] + list_filter = ["child__name"] + search_fields = ["child__name", "child__age"] + list_select_related = ["child"] class ChildAdmin(admin.ModelAdmin): - list_display = ['name', 'parent'] + list_display = ["name", "parent"] list_per_page = 10 - list_filter = ['parent', 'age'] + list_filter = ["parent", "age"] def get_queryset(self, request): return super().get_queryset(request).select_related("parent") @@ -56,32 +58,32 @@ class CustomPaginationAdmin(ChildAdmin): class FilteredChildAdmin(admin.ModelAdmin): - list_display = ['name', 'parent'] + list_display = ["name", "parent"] list_per_page = 10 def get_queryset(self, request): - return super().get_queryset(request).filter(name__contains='filtered') + return super().get_queryset(request).filter(name__contains="filtered") class BandAdmin(admin.ModelAdmin): - list_filter = ['genres'] + list_filter = ["genres"] class NrOfMembersFilter(admin.SimpleListFilter): - title = 'number of members' - parameter_name = 'nr_of_members_partition' + title = "number of members" + parameter_name = "nr_of_members_partition" def lookups(self, request, model_admin): return [ - ('5', '0 - 5'), - ('more', 'more than 5'), + ("5", "0 - 5"), + ("more", "more than 5"), ] def queryset(self, request, queryset): value = self.value() - if value == '5': + if value == "5": return queryset.filter(nr_of_members__lte=5) - if value == 'more': + if value == "more": return queryset.filter(nr_of_members__gt=5) @@ -93,44 +95,44 @@ site.register(Band, BandCallableFilterAdmin) class GroupAdmin(admin.ModelAdmin): - list_filter = ['members'] + list_filter = ["members"] class ConcertAdmin(admin.ModelAdmin): - list_filter = ['group__members'] - search_fields = ['group__members__name'] + list_filter = ["group__members"] + search_fields = ["group__members__name"] class QuartetAdmin(admin.ModelAdmin): - list_filter = ['members'] + list_filter = ["members"] class ChordsBandAdmin(admin.ModelAdmin): - list_filter = ['members'] + list_filter = ["members"] class InvitationAdmin(admin.ModelAdmin): - list_display = ('band', 'player') - list_select_related = ('player',) + list_display = ("band", "player") + list_select_related = ("player",) class DynamicListDisplayChildAdmin(admin.ModelAdmin): - list_display = ('parent', 'name', 'age') + list_display = ("parent", "name", "age") def get_list_display(self, request): my_list_display = super().get_list_display(request) - if request.user.username == 'noparents': + if request.user.username == "noparents": my_list_display = list(my_list_display) - my_list_display.remove('parent') + my_list_display.remove("parent") return my_list_display class DynamicListDisplayLinksChildAdmin(admin.ModelAdmin): - list_display = ('parent', 'name', 'age') - list_display_links = ['parent', 'name'] + list_display = ("parent", "name", "age") + list_display_links = ["parent", "name"] def get_list_display_links(self, request, list_display): - return ['age'] + return ["age"] site.register(Child, DynamicListDisplayChildAdmin) @@ -138,8 +140,8 @@ site.register(Child, DynamicListDisplayChildAdmin) class NoListDisplayLinksParentAdmin(admin.ModelAdmin): list_display_links = None - list_display = ['name'] - list_editable = ['name'] + list_display = ["name"] + list_editable = ["name"] actions_on_bottom = True @@ -148,8 +150,8 @@ site.register(Parent, NoListDisplayLinksParentAdmin) class SwallowAdmin(admin.ModelAdmin): actions = None # prevent ['action_checkbox'] + list(list_display) - list_display = ('origin', 'load', 'speed', 'swallowonetoone') - list_editable = ['load', 'speed'] + list_display = ("origin", "load", "speed", "swallowonetoone") + list_editable = ["load", "speed"] list_per_page = 3 @@ -157,29 +159,29 @@ site.register(Swallow, SwallowAdmin) class DynamicListFilterChildAdmin(admin.ModelAdmin): - list_filter = ('parent', 'name', 'age') + list_filter = ("parent", "name", "age") def get_list_filter(self, request): my_list_filter = super().get_list_filter(request) - if request.user.username == 'noparents': + if request.user.username == "noparents": my_list_filter = list(my_list_filter) - my_list_filter.remove('parent') + my_list_filter.remove("parent") return my_list_filter class DynamicSearchFieldsChildAdmin(admin.ModelAdmin): - search_fields = ('name',) + search_fields = ("name",) def get_search_fields(self, request): search_fields = super().get_search_fields(request) - search_fields += ('age',) + search_fields += ("age",) return search_fields class EmptyValueChildAdmin(admin.ModelAdmin): - empty_value_display = '-empty-' - list_display = ('name', 'age_display', 'age') + empty_value_display = "-empty-" + list_display = ("name", "age_display", "age") - @admin.display(empty_value='†') + @admin.display(empty_value="†") def age_display(self, obj): return obj.age diff --git a/tests/admin_changelist/models.py b/tests/admin_changelist/models.py index 81d7fdfb3a..180c38428a 100644 --- a/tests/admin_changelist/models.py +++ b/tests/admin_changelist/models.py @@ -38,7 +38,7 @@ class Musician(models.Model): class Group(models.Model): name = models.CharField(max_length=30) - members = models.ManyToManyField(Musician, through='Membership') + members = models.ManyToManyField(Musician, through="Membership") def __str__(self): return self.name @@ -65,7 +65,7 @@ class ChordsMusician(Musician): class ChordsBand(models.Model): name = models.CharField(max_length=30) - members = models.ManyToManyField(ChordsMusician, through='Invitation') + members = models.ManyToManyField(ChordsMusician, through="Invitation") class Invitation(models.Model): @@ -81,7 +81,7 @@ class Swallow(models.Model): speed = models.FloatField() class Meta: - ordering = ('speed', 'load') + ordering = ("speed", "load") class SwallowOneToOne(models.Model): @@ -93,12 +93,13 @@ class UnorderedObject(models.Model): Model without any defined `Meta.ordering`. Refs #17198. """ + bool = models.BooleanField(default=True) class OrderedObjectManager(models.Manager): def get_queryset(self): - return super().get_queryset().order_by('number') + return super().get_queryset().order_by("number") class OrderedObject(models.Model): @@ -106,9 +107,10 @@ class OrderedObject(models.Model): Model with Manager that defines a default order. Refs #17198. """ + name = models.CharField(max_length=255) bool = models.BooleanField(default=True) - number = models.IntegerField(default=0, db_column='number_val') + number = models.IntegerField(default=0, db_column="number_val") objects = OrderedObjectManager() diff --git a/tests/admin_changelist/test_date_hierarchy.py b/tests/admin_changelist/test_date_hierarchy.py index a321650b32..a8c10f7cd8 100644 --- a/tests/admin_changelist/test_date_hierarchy.py +++ b/tests/admin_changelist/test_date_hierarchy.py @@ -5,7 +5,8 @@ from django.contrib.auth.models import User from django.test import RequestFactory, TestCase from django.utils.timezone import make_aware -from .admin import EventAdmin, site as custom_site +from .admin import EventAdmin +from .admin import site as custom_site from .models import Event @@ -14,34 +15,48 @@ class DateHierarchyTests(TestCase): @classmethod def setUpTestData(cls): - cls.superuser = User.objects.create_superuser(username='super', email='a@b.com', password='xxx') + cls.superuser = User.objects.create_superuser( + username="super", email="a@b.com", password="xxx" + ) def assertDateParams(self, query, expected_from_date, expected_to_date): - query = {'date__%s' % field: val for field, val in query.items()} - request = self.factory.get('/', query) + query = {"date__%s" % field: val for field, val in query.items()} + request = self.factory.get("/", query) request.user = self.superuser changelist = EventAdmin(Event, custom_site).get_changelist_instance(request) _, _, lookup_params, *_ = changelist.get_filters(request) - self.assertEqual(lookup_params['date__gte'], expected_from_date) - self.assertEqual(lookup_params['date__lt'], expected_to_date) + self.assertEqual(lookup_params["date__gte"], expected_from_date) + self.assertEqual(lookup_params["date__lt"], expected_to_date) def test_bounded_params(self): tests = ( - ({'year': 2017}, datetime(2017, 1, 1), datetime(2018, 1, 1)), - ({'year': 2017, 'month': 2}, datetime(2017, 2, 1), datetime(2017, 3, 1)), - ({'year': 2017, 'month': 12}, datetime(2017, 12, 1), datetime(2018, 1, 1)), - ({'year': 2017, 'month': 12, 'day': 15}, datetime(2017, 12, 15), datetime(2017, 12, 16)), - ({'year': 2017, 'month': 12, 'day': 31}, datetime(2017, 12, 31), datetime(2018, 1, 1)), - ({'year': 2017, 'month': 2, 'day': 28}, datetime(2017, 2, 28), datetime(2017, 3, 1)), + ({"year": 2017}, datetime(2017, 1, 1), datetime(2018, 1, 1)), + ({"year": 2017, "month": 2}, datetime(2017, 2, 1), datetime(2017, 3, 1)), + ({"year": 2017, "month": 12}, datetime(2017, 12, 1), datetime(2018, 1, 1)), + ( + {"year": 2017, "month": 12, "day": 15}, + datetime(2017, 12, 15), + datetime(2017, 12, 16), + ), + ( + {"year": 2017, "month": 12, "day": 31}, + datetime(2017, 12, 31), + datetime(2018, 1, 1), + ), + ( + {"year": 2017, "month": 2, "day": 28}, + datetime(2017, 2, 28), + datetime(2017, 3, 1), + ), ) for query, expected_from_date, expected_to_date in tests: with self.subTest(query=query): self.assertDateParams(query, expected_from_date, expected_to_date) def test_bounded_params_with_time_zone(self): - with self.settings(USE_TZ=True, TIME_ZONE='Asia/Jerusalem'): + with self.settings(USE_TZ=True, TIME_ZONE="Asia/Jerusalem"): self.assertDateParams( - {'year': 2017, 'month': 2, 'day': 28}, + {"year": 2017, "month": 2, "day": 28}, make_aware(datetime(2017, 2, 28)), make_aware(datetime(2017, 3, 1)), ) @@ -49,31 +64,33 @@ class DateHierarchyTests(TestCase): def test_bounded_params_with_dst_time_zone(self): tests = [ # Northern hemisphere. - ('Asia/Jerusalem', 3), - ('Asia/Jerusalem', 10), + ("Asia/Jerusalem", 3), + ("Asia/Jerusalem", 10), # Southern hemisphere. - ('Pacific/Chatham', 4), - ('Pacific/Chatham', 9), + ("Pacific/Chatham", 4), + ("Pacific/Chatham", 9), ] for time_zone, month in tests: with self.subTest(time_zone=time_zone, month=month): with self.settings(USE_TZ=True, TIME_ZONE=time_zone): self.assertDateParams( - {'year': 2019, 'month': month}, + {"year": 2019, "month": month}, make_aware(datetime(2019, month, 1)), make_aware(datetime(2019, month + 1, 1)), ) def test_invalid_params(self): tests = ( - {'year': 'x'}, - {'year': 2017, 'month': 'x'}, - {'year': 2017, 'month': 12, 'day': 'x'}, - {'year': 2017, 'month': 13}, - {'year': 2017, 'month': 12, 'day': 32}, - {'year': 2017, 'month': 0}, - {'year': 2017, 'month': 12, 'day': 0}, + {"year": "x"}, + {"year": 2017, "month": "x"}, + {"year": 2017, "month": 12, "day": "x"}, + {"year": 2017, "month": 13}, + {"year": 2017, "month": 12, "day": 32}, + {"year": 2017, "month": 0}, + {"year": 2017, "month": 12, "day": 0}, ) for invalid_query in tests: - with self.subTest(query=invalid_query), self.assertRaises(IncorrectLookupParameters): + with self.subTest(query=invalid_query), self.assertRaises( + IncorrectLookupParameters + ): self.assertDateParams(invalid_query, None, None) diff --git a/tests/admin_changelist/tests.py b/tests/admin_changelist/tests.py index 86fcab531a..7d6deced7e 100644 --- a/tests/admin_changelist/tests.py +++ b/tests/admin_changelist/tests.py @@ -6,7 +6,12 @@ from django.contrib.admin.options import IncorrectLookupParameters from django.contrib.admin.templatetags.admin_list import pagination from django.contrib.admin.tests import AdminSeleniumTestCase from django.contrib.admin.views.main import ( - ALL_VAR, IS_POPUP_VAR, ORDER_VAR, PAGE_VAR, SEARCH_VAR, TO_FIELD_VAR, + ALL_VAR, + IS_POPUP_VAR, + ORDER_VAR, + PAGE_VAR, + SEARCH_VAR, + TO_FIELD_VAR, ) from django.contrib.auth.models import User from django.contrib.contenttypes.models import ContentType @@ -18,36 +23,64 @@ from django.db.models.lookups import Contains, Exact from django.template import Context, Template, TemplateSyntaxError from django.test import TestCase, override_settings from django.test.client import RequestFactory -from django.test.utils import ( - CaptureQueriesContext, isolate_apps, register_lookup, -) +from django.test.utils import CaptureQueriesContext, isolate_apps, register_lookup from django.urls import reverse from django.utils import formats from .admin import ( - BandAdmin, ChildAdmin, ChordsBandAdmin, ConcertAdmin, - CustomPaginationAdmin, CustomPaginator, DynamicListDisplayChildAdmin, - DynamicListDisplayLinksChildAdmin, DynamicListFilterChildAdmin, - DynamicSearchFieldsChildAdmin, EmptyValueChildAdmin, EventAdmin, - FilteredChildAdmin, GroupAdmin, InvitationAdmin, - NoListDisplayLinksParentAdmin, ParentAdmin, ParentAdminTwoSearchFields, - QuartetAdmin, SwallowAdmin, site as custom_site, + BandAdmin, + ChildAdmin, + ChordsBandAdmin, + ConcertAdmin, + CustomPaginationAdmin, + CustomPaginator, + DynamicListDisplayChildAdmin, + DynamicListDisplayLinksChildAdmin, + DynamicListFilterChildAdmin, + DynamicSearchFieldsChildAdmin, + EmptyValueChildAdmin, + EventAdmin, + FilteredChildAdmin, + GroupAdmin, + InvitationAdmin, + NoListDisplayLinksParentAdmin, + ParentAdmin, + ParentAdminTwoSearchFields, + QuartetAdmin, + SwallowAdmin, ) +from .admin import site as custom_site from .models import ( - Band, CharPK, Child, ChordsBand, ChordsMusician, Concert, CustomIdUser, - Event, Genre, Group, Invitation, Membership, Musician, OrderedObject, - Parent, Quartet, Swallow, SwallowOneToOne, UnorderedObject, + Band, + CharPK, + Child, + ChordsBand, + ChordsMusician, + Concert, + CustomIdUser, + Event, + Genre, + Group, + Invitation, + Membership, + Musician, + OrderedObject, + Parent, + Quartet, + Swallow, + SwallowOneToOne, + UnorderedObject, ) def build_tbody_html(pk, href, extra_fields): return ( - '<tbody><tr>' + "<tbody><tr>" '<td class="action-checkbox">' '<input type="checkbox" name="_selected_action" value="{}" ' 'class="action-select"></td>' '<th class="field-name"><a href="{}">name</a></th>' - '{}</tr></tbody>' + "{}</tr></tbody>" ).format(pk, href, extra_fields) @@ -57,10 +90,14 @@ class ChangeListTests(TestCase): @classmethod def setUpTestData(cls): - cls.superuser = User.objects.create_superuser(username='super', email='a@b.com', password='xxx') + cls.superuser = User.objects.create_superuser( + username="super", email="a@b.com", password="xxx" + ) def _create_superuser(self, username): - return User.objects.create_superuser(username=username, email='a@b.com', password='xxx') + return User.objects.create_superuser( + username=username, email="a@b.com", password="xxx" + ) def _mocked_authenticated_request(self, url, user): request = self.factory.get(url) @@ -69,36 +106,36 @@ class ChangeListTests(TestCase): def test_repr(self): m = ChildAdmin(Child, custom_site) - request = self.factory.get('/child/') + request = self.factory.get("/child/") request.user = self.superuser cl = m.get_changelist_instance(request) - self.assertEqual(repr(cl), '<ChangeList: model=Child model_admin=ChildAdmin>') + self.assertEqual(repr(cl), "<ChangeList: model=Child model_admin=ChildAdmin>") def test_specified_ordering_by_f_expression(self): class OrderedByFBandAdmin(admin.ModelAdmin): - list_display = ['name', 'genres', 'nr_of_members'] + list_display = ["name", "genres", "nr_of_members"] ordering = ( - F('nr_of_members').desc(nulls_last=True), - Upper(F('name')).asc(), - F('genres').asc(), + F("nr_of_members").desc(nulls_last=True), + Upper(F("name")).asc(), + F("genres").asc(), ) m = OrderedByFBandAdmin(Band, custom_site) - request = self.factory.get('/band/') + request = self.factory.get("/band/") request.user = self.superuser cl = m.get_changelist_instance(request) - self.assertEqual(cl.get_ordering_field_columns(), {3: 'desc', 2: 'asc'}) + self.assertEqual(cl.get_ordering_field_columns(), {3: "desc", 2: "asc"}) def test_specified_ordering_by_f_expression_without_asc_desc(self): class OrderedByFBandAdmin(admin.ModelAdmin): - list_display = ['name', 'genres', 'nr_of_members'] - ordering = (F('nr_of_members'), Upper('name'), F('genres')) + list_display = ["name", "genres", "nr_of_members"] + ordering = (F("nr_of_members"), Upper("name"), F("genres")) m = OrderedByFBandAdmin(Band, custom_site) - request = self.factory.get('/band/') + request = self.factory.get("/band/") request.user = self.superuser cl = m.get_changelist_instance(request) - self.assertEqual(cl.get_ordering_field_columns(), {3: 'asc', 2: 'asc'}) + self.assertEqual(cl.get_ordering_field_columns(), {3: "asc", 2: "asc"}) def test_select_related_preserved(self): """ @@ -106,85 +143,85 @@ class ChangeListTests(TestCase): overwrite a custom select_related provided by ModelAdmin.get_queryset(). """ m = ChildAdmin(Child, custom_site) - request = self.factory.get('/child/') + request = self.factory.get("/child/") request.user = self.superuser cl = m.get_changelist_instance(request) - self.assertEqual(cl.queryset.query.select_related, {'parent': {}}) + self.assertEqual(cl.queryset.query.select_related, {"parent": {}}) def test_select_related_preserved_when_multi_valued_in_search_fields(self): - parent = Parent.objects.create(name='Mary') - Child.objects.create(parent=parent, name='Danielle') - Child.objects.create(parent=parent, name='Daniel') + parent = Parent.objects.create(name="Mary") + Child.objects.create(parent=parent, name="Danielle") + Child.objects.create(parent=parent, name="Daniel") m = ParentAdmin(Parent, custom_site) - request = self.factory.get('/parent/', data={SEARCH_VAR: 'daniel'}) + request = self.factory.get("/parent/", data={SEARCH_VAR: "daniel"}) request.user = self.superuser cl = m.get_changelist_instance(request) self.assertEqual(cl.queryset.count(), 1) # select_related is preserved. - self.assertEqual(cl.queryset.query.select_related, {'child': {}}) + self.assertEqual(cl.queryset.query.select_related, {"child": {}}) def test_select_related_as_tuple(self): ia = InvitationAdmin(Invitation, custom_site) - request = self.factory.get('/invitation/') + request = self.factory.get("/invitation/") request.user = self.superuser cl = ia.get_changelist_instance(request) - self.assertEqual(cl.queryset.query.select_related, {'player': {}}) + self.assertEqual(cl.queryset.query.select_related, {"player": {}}) def test_select_related_as_empty_tuple(self): ia = InvitationAdmin(Invitation, custom_site) ia.list_select_related = () - request = self.factory.get('/invitation/') + request = self.factory.get("/invitation/") request.user = self.superuser cl = ia.get_changelist_instance(request) self.assertIs(cl.queryset.query.select_related, False) def test_get_select_related_custom_method(self): class GetListSelectRelatedAdmin(admin.ModelAdmin): - list_display = ('band', 'player') + list_display = ("band", "player") def get_list_select_related(self, request): - return ('band', 'player') + return ("band", "player") ia = GetListSelectRelatedAdmin(Invitation, custom_site) - request = self.factory.get('/invitation/') + request = self.factory.get("/invitation/") request.user = self.superuser cl = ia.get_changelist_instance(request) - self.assertEqual(cl.queryset.query.select_related, {'player': {}, 'band': {}}) + self.assertEqual(cl.queryset.query.select_related, {"player": {}, "band": {}}) def test_many_search_terms(self): - parent = Parent.objects.create(name='Mary') - Child.objects.create(parent=parent, name='Danielle') - Child.objects.create(parent=parent, name='Daniel') + parent = Parent.objects.create(name="Mary") + Child.objects.create(parent=parent, name="Danielle") + Child.objects.create(parent=parent, name="Daniel") m = ParentAdmin(Parent, custom_site) - request = self.factory.get('/parent/', data={SEARCH_VAR: 'daniel ' * 80}) + request = self.factory.get("/parent/", data={SEARCH_VAR: "daniel " * 80}) request.user = self.superuser cl = m.get_changelist_instance(request) with CaptureQueriesContext(connection) as context: object_count = cl.queryset.count() self.assertEqual(object_count, 1) - self.assertEqual(context.captured_queries[0]['sql'].count('JOIN'), 1) + self.assertEqual(context.captured_queries[0]["sql"].count("JOIN"), 1) def test_related_field_multiple_search_terms(self): """ Searches over multi-valued relationships return rows from related models only when all searched fields match that row. """ - parent = Parent.objects.create(name='Mary') - Child.objects.create(parent=parent, name='Danielle', age=18) - Child.objects.create(parent=parent, name='Daniel', age=19) + parent = Parent.objects.create(name="Mary") + Child.objects.create(parent=parent, name="Danielle", age=18) + Child.objects.create(parent=parent, name="Daniel", age=19) m = ParentAdminTwoSearchFields(Parent, custom_site) - request = self.factory.get('/parent/', data={SEARCH_VAR: 'danielle 19'}) + request = self.factory.get("/parent/", data={SEARCH_VAR: "danielle 19"}) request.user = self.superuser cl = m.get_changelist_instance(request) self.assertEqual(cl.queryset.count(), 0) - request = self.factory.get('/parent/', data={SEARCH_VAR: 'daniel 19'}) + request = self.factory.get("/parent/", data={SEARCH_VAR: "daniel 19"}) request.user = self.superuser cl = m.get_changelist_instance(request) self.assertEqual(cl.queryset.count(), 1) @@ -194,78 +231,108 @@ class ChangeListTests(TestCase): Regression test for #14982: EMPTY_CHANGELIST_VALUE should be honored for relationship fields """ - new_child = Child.objects.create(name='name', parent=None) - request = self.factory.get('/child/') + new_child = Child.objects.create(name="name", parent=None) + request = self.factory.get("/child/") request.user = self.superuser m = ChildAdmin(Child, custom_site) cl = m.get_changelist_instance(request) cl.formset = None - template = Template('{% load admin_list %}{% spaceless %}{% result_list cl %}{% endspaceless %}') - context = Context({'cl': cl, 'opts': Child._meta}) + template = Template( + "{% load admin_list %}{% spaceless %}{% result_list cl %}{% endspaceless %}" + ) + context = Context({"cl": cl, "opts": Child._meta}) table_output = template.render(context) - link = reverse('admin:admin_changelist_child_change', args=(new_child.id,)) - row_html = build_tbody_html(new_child.id, link, '<td class="field-parent nowrap">-</td>') - self.assertNotEqual(table_output.find(row_html), -1, 'Failed to find expected row element: %s' % table_output) + link = reverse("admin:admin_changelist_child_change", args=(new_child.id,)) + row_html = build_tbody_html( + new_child.id, link, '<td class="field-parent nowrap">-</td>' + ) + self.assertNotEqual( + table_output.find(row_html), + -1, + "Failed to find expected row element: %s" % table_output, + ) def test_result_list_set_empty_value_display_on_admin_site(self): """ Empty value display can be set on AdminSite. """ - new_child = Child.objects.create(name='name', parent=None) - request = self.factory.get('/child/') + new_child = Child.objects.create(name="name", parent=None) + request = self.factory.get("/child/") request.user = self.superuser # Set a new empty display value on AdminSite. - admin.site.empty_value_display = '???' + admin.site.empty_value_display = "???" m = ChildAdmin(Child, admin.site) cl = m.get_changelist_instance(request) cl.formset = None - template = Template('{% load admin_list %}{% spaceless %}{% result_list cl %}{% endspaceless %}') - context = Context({'cl': cl, 'opts': Child._meta}) + template = Template( + "{% load admin_list %}{% spaceless %}{% result_list cl %}{% endspaceless %}" + ) + context = Context({"cl": cl, "opts": Child._meta}) table_output = template.render(context) - link = reverse('admin:admin_changelist_child_change', args=(new_child.id,)) - row_html = build_tbody_html(new_child.id, link, '<td class="field-parent nowrap">???</td>') - self.assertNotEqual(table_output.find(row_html), -1, 'Failed to find expected row element: %s' % table_output) + link = reverse("admin:admin_changelist_child_change", args=(new_child.id,)) + row_html = build_tbody_html( + new_child.id, link, '<td class="field-parent nowrap">???</td>' + ) + self.assertNotEqual( + table_output.find(row_html), + -1, + "Failed to find expected row element: %s" % table_output, + ) def test_result_list_set_empty_value_display_in_model_admin(self): """ Empty value display can be set in ModelAdmin or individual fields. """ - new_child = Child.objects.create(name='name', parent=None) - request = self.factory.get('/child/') + new_child = Child.objects.create(name="name", parent=None) + request = self.factory.get("/child/") request.user = self.superuser m = EmptyValueChildAdmin(Child, admin.site) cl = m.get_changelist_instance(request) cl.formset = None - template = Template('{% load admin_list %}{% spaceless %}{% result_list cl %}{% endspaceless %}') - context = Context({'cl': cl, 'opts': Child._meta}) + template = Template( + "{% load admin_list %}{% spaceless %}{% result_list cl %}{% endspaceless %}" + ) + context = Context({"cl": cl, "opts": Child._meta}) table_output = template.render(context) - link = reverse('admin:admin_changelist_child_change', args=(new_child.id,)) + link = reverse("admin:admin_changelist_child_change", args=(new_child.id,)) row_html = build_tbody_html( new_child.id, link, '<td class="field-age_display">&dagger;</td>' - '<td class="field-age">-empty-</td>' + '<td class="field-age">-empty-</td>', + ) + self.assertNotEqual( + table_output.find(row_html), + -1, + "Failed to find expected row element: %s" % table_output, ) - self.assertNotEqual(table_output.find(row_html), -1, 'Failed to find expected row element: %s' % table_output) def test_result_list_html(self): """ Inclusion tag result_list generates a table when with default ModelAdmin settings. """ - new_parent = Parent.objects.create(name='parent') - new_child = Child.objects.create(name='name', parent=new_parent) - request = self.factory.get('/child/') + new_parent = Parent.objects.create(name="parent") + new_child = Child.objects.create(name="name", parent=new_parent) + request = self.factory.get("/child/") request.user = self.superuser m = ChildAdmin(Child, custom_site) cl = m.get_changelist_instance(request) cl.formset = None - template = Template('{% load admin_list %}{% spaceless %}{% result_list cl %}{% endspaceless %}') - context = Context({'cl': cl, 'opts': Child._meta}) + template = Template( + "{% load admin_list %}{% spaceless %}{% result_list cl %}{% endspaceless %}" + ) + context = Context({"cl": cl, "opts": Child._meta}) table_output = template.render(context) - link = reverse('admin:admin_changelist_child_change', args=(new_child.id,)) - row_html = build_tbody_html(new_child.id, link, '<td class="field-parent nowrap">%s</td>' % new_parent) - self.assertNotEqual(table_output.find(row_html), -1, 'Failed to find expected row element: %s' % table_output) + link = reverse("admin:admin_changelist_child_change", args=(new_child.id,)) + row_html = build_tbody_html( + new_child.id, link, '<td class="field-parent nowrap">%s</td>' % new_parent + ) + self.assertNotEqual( + table_output.find(row_html), + -1, + "Failed to find expected row element: %s" % table_output, + ) def test_result_list_editable_html(self): """ @@ -276,29 +343,33 @@ class ChangeListTests(TestCase): when list_editable is enabled are rendered in a div outside the table. """ - new_parent = Parent.objects.create(name='parent') - new_child = Child.objects.create(name='name', parent=new_parent) - request = self.factory.get('/child/') + new_parent = Parent.objects.create(name="parent") + new_child = Child.objects.create(name="name", parent=new_parent) + request = self.factory.get("/child/") request.user = self.superuser m = ChildAdmin(Child, custom_site) # Test with list_editable fields - m.list_display = ['id', 'name', 'parent'] - m.list_display_links = ['id'] - m.list_editable = ['name'] + m.list_display = ["id", "name", "parent"] + m.list_display_links = ["id"] + m.list_editable = ["name"] cl = m.get_changelist_instance(request) FormSet = m.get_changelist_formset(request) cl.formset = FormSet(queryset=cl.result_list) - template = Template('{% load admin_list %}{% spaceless %}{% result_list cl %}{% endspaceless %}') - context = Context({'cl': cl, 'opts': Child._meta}) + template = Template( + "{% load admin_list %}{% spaceless %}{% result_list cl %}{% endspaceless %}" + ) + context = Context({"cl": cl, "opts": Child._meta}) table_output = template.render(context) # make sure that hidden fields are in the correct place hiddenfields_div = ( '<div class="hiddenfields">' '<input type="hidden" name="form-0-id" value="%d" id="id_form-0-id">' - '</div>' + "</div>" ) % new_child.id - self.assertInHTML(hiddenfields_div, table_output, msg_prefix='Failed to find hidden fields') + self.assertInHTML( + hiddenfields_div, table_output, msg_prefix="Failed to find hidden fields" + ) # make sure that list editable fields are rendered in divs correctly editable_name_field = ( @@ -315,26 +386,26 @@ class ChangeListTests(TestCase): """ Regression test for #14312: list_editable with pagination """ - new_parent = Parent.objects.create(name='parent') + new_parent = Parent.objects.create(name="parent") for i in range(1, 201): - Child.objects.create(name='name %s' % i, parent=new_parent) - request = self.factory.get('/child/', data={'p': -1}) # Anything outside range + Child.objects.create(name="name %s" % i, parent=new_parent) + request = self.factory.get("/child/", data={"p": -1}) # Anything outside range request.user = self.superuser m = ChildAdmin(Child, custom_site) # Test with list_editable fields - m.list_display = ['id', 'name', 'parent'] - m.list_display_links = ['id'] - m.list_editable = ['name'] + m.list_display = ["id", "name", "parent"] + m.list_display_links = ["id"] + m.list_editable = ["name"] with self.assertRaises(IncorrectLookupParameters): m.get_changelist_instance(request) def test_custom_paginator(self): - new_parent = Parent.objects.create(name='parent') + new_parent = Parent.objects.create(name="parent") for i in range(1, 201): - Child.objects.create(name='name %s' % i, parent=new_parent) + Child.objects.create(name="name %s" % i, parent=new_parent) - request = self.factory.get('/child/') + request = self.factory.get("/child/") request.user = self.superuser m = CustomPaginationAdmin(Child, custom_site) @@ -347,14 +418,14 @@ class ChangeListTests(TestCase): Regression test for #13902: When using a ManyToMany in list_filter, results shouldn't appear more than once. Basic ManyToMany. """ - blues = Genre.objects.create(name='Blues') - band = Band.objects.create(name='B.B. King Review', nr_of_members=11) + blues = Genre.objects.create(name="Blues") + band = Band.objects.create(name="B.B. King Review", nr_of_members=11) band.genres.add(blues) band.genres.add(blues) m = BandAdmin(Band, custom_site) - request = self.factory.get('/band/', data={'genres': blues.pk}) + request = self.factory.get("/band/", data={"genres": blues.pk}) request.user = self.superuser cl = m.get_changelist_instance(request) @@ -372,13 +443,13 @@ class ChangeListTests(TestCase): Regression test for #13902: When using a ManyToMany in list_filter, results shouldn't appear more than once. With an intermediate model. """ - lead = Musician.objects.create(name='Vox') - band = Group.objects.create(name='The Hype') - Membership.objects.create(group=band, music=lead, role='lead voice') - Membership.objects.create(group=band, music=lead, role='bass player') + lead = Musician.objects.create(name="Vox") + band = Group.objects.create(name="The Hype") + Membership.objects.create(group=band, music=lead, role="lead voice") + Membership.objects.create(group=band, music=lead, role="bass player") m = GroupAdmin(Group, custom_site) - request = self.factory.get('/group/', data={'members': lead.pk}) + request = self.factory.get("/group/", data={"members": lead.pk}) request.user = self.superuser cl = m.get_changelist_instance(request) @@ -396,14 +467,14 @@ class ChangeListTests(TestCase): When using a ManyToMany in list_filter at the second level behind a ForeignKey, results shouldn't appear more than once. """ - lead = Musician.objects.create(name='Vox') - band = Group.objects.create(name='The Hype') - Concert.objects.create(name='Woodstock', group=band) - Membership.objects.create(group=band, music=lead, role='lead voice') - Membership.objects.create(group=band, music=lead, role='bass player') + lead = Musician.objects.create(name="Vox") + band = Group.objects.create(name="The Hype") + Concert.objects.create(name="Woodstock", group=band) + Membership.objects.create(group=band, music=lead, role="lead voice") + Membership.objects.create(group=band, music=lead, role="bass player") m = ConcertAdmin(Concert, custom_site) - request = self.factory.get('/concert/', data={'group__members': lead.pk}) + request = self.factory.get("/concert/", data={"group__members": lead.pk}) request.user = self.superuser cl = m.get_changelist_instance(request) @@ -422,13 +493,13 @@ class ChangeListTests(TestCase): results shouldn't appear more than once. Model managed in the admin inherits from the one that defines the relationship. """ - lead = Musician.objects.create(name='John') - four = Quartet.objects.create(name='The Beatles') - Membership.objects.create(group=four, music=lead, role='lead voice') - Membership.objects.create(group=four, music=lead, role='guitar player') + lead = Musician.objects.create(name="John") + four = Quartet.objects.create(name="The Beatles") + Membership.objects.create(group=four, music=lead, role="lead voice") + Membership.objects.create(group=four, music=lead, role="guitar player") m = QuartetAdmin(Quartet, custom_site) - request = self.factory.get('/quartet/', data={'members': lead.pk}) + request = self.factory.get("/quartet/", data={"members": lead.pk}) request.user = self.superuser cl = m.get_changelist_instance(request) @@ -447,13 +518,13 @@ class ChangeListTests(TestCase): results shouldn't appear more than once. Target of the relationship inherits from another. """ - lead = ChordsMusician.objects.create(name='Player A') - three = ChordsBand.objects.create(name='The Chords Trio') - Invitation.objects.create(band=three, player=lead, instrument='guitar') - Invitation.objects.create(band=three, player=lead, instrument='bass') + lead = ChordsMusician.objects.create(name="Player A") + three = ChordsBand.objects.create(name="The Chords Trio") + Invitation.objects.create(band=three, player=lead, instrument="guitar") + Invitation.objects.create(band=three, player=lead, instrument="bass") m = ChordsBandAdmin(ChordsBand, custom_site) - request = self.factory.get('/chordsband/', data={'members': lead.pk}) + request = self.factory.get("/chordsband/", data={"members": lead.pk}) request.user = self.superuser cl = m.get_changelist_instance(request) @@ -471,13 +542,13 @@ class ChangeListTests(TestCase): Regressions tests for #15819: If a field listed in list_filters is a non-unique related object, results shouldn't appear more than once. """ - parent = Parent.objects.create(name='Mary') + parent = Parent.objects.create(name="Mary") # Two children with the same name - Child.objects.create(parent=parent, name='Daniel') - Child.objects.create(parent=parent, name='Daniel') + Child.objects.create(parent=parent, name="Daniel") + Child.objects.create(parent=parent, name="Daniel") m = ParentAdmin(Parent, custom_site) - request = self.factory.get('/parent/', data={'child__name': 'Daniel'}) + request = self.factory.get("/parent/", data={"child__name": "Daniel"}) request.user = self.superuser cl = m.get_changelist_instance(request) @@ -491,12 +562,12 @@ class ChangeListTests(TestCase): def test_changelist_search_form_validation(self): m = ConcertAdmin(Concert, custom_site) tests = [ - ({SEARCH_VAR: '\x00'}, 'Null characters are not allowed.'), - ({SEARCH_VAR: 'some\x00thing'}, 'Null characters are not allowed.'), + ({SEARCH_VAR: "\x00"}, "Null characters are not allowed."), + ({SEARCH_VAR: "some\x00thing"}, "Null characters are not allowed."), ] for case, error in tests: with self.subTest(case=case): - request = self.factory.get('/concert/', case) + request = self.factory.get("/concert/", case) request.user = self.superuser request._messages = CookieStorage(request) m.get_changelist_instance(request) @@ -509,12 +580,12 @@ class ChangeListTests(TestCase): Regressions tests for #15819: If a field listed in search_fields is a non-unique related object, Exists() must be applied. """ - parent = Parent.objects.create(name='Mary') - Child.objects.create(parent=parent, name='Danielle') - Child.objects.create(parent=parent, name='Daniel') + parent = Parent.objects.create(name="Mary") + Child.objects.create(parent=parent, name="Danielle") + Child.objects.create(parent=parent, name="Daniel") m = ParentAdmin(Parent, custom_site) - request = self.factory.get('/parent/', data={SEARCH_VAR: 'daniel'}) + request = self.factory.get("/parent/", data={SEARCH_VAR: "daniel"}) request.user = self.superuser cl = m.get_changelist_instance(request) @@ -531,14 +602,14 @@ class ChangeListTests(TestCase): ForeignKey, Exists() must be applied and results shouldn't appear more than once. """ - lead = Musician.objects.create(name='Vox') - band = Group.objects.create(name='The Hype') - Concert.objects.create(name='Woodstock', group=band) - Membership.objects.create(group=band, music=lead, role='lead voice') - Membership.objects.create(group=band, music=lead, role='bass player') + lead = Musician.objects.create(name="Vox") + band = Group.objects.create(name="The Hype") + Concert.objects.create(name="Woodstock", group=band) + Membership.objects.create(group=band, music=lead, role="lead voice") + Membership.objects.create(group=band, music=lead, role="bass player") m = ConcertAdmin(Concert, custom_site) - request = self.factory.get('/concert/', data={SEARCH_VAR: 'vox'}) + request = self.factory.get("/concert/", data={SEARCH_VAR: "vox"}) request.user = self.superuser cl = m.get_changelist_instance(request) @@ -554,139 +625,143 @@ class ChangeListTests(TestCase): All rows containing each of the searched words are returned, where each word must be in one of search_fields. """ - band_duo = Group.objects.create(name='Duo') - band_hype = Group.objects.create(name='The Hype') - mary = Musician.objects.create(name='Mary Halvorson') - jonathan = Musician.objects.create(name='Jonathan Finlayson') + band_duo = Group.objects.create(name="Duo") + band_hype = Group.objects.create(name="The Hype") + mary = Musician.objects.create(name="Mary Halvorson") + jonathan = Musician.objects.create(name="Jonathan Finlayson") band_duo.members.set([mary, jonathan]) - Concert.objects.create(name='Tiny desk concert', group=band_duo) - Concert.objects.create(name='Woodstock concert', group=band_hype) + Concert.objects.create(name="Tiny desk concert", group=band_duo) + Concert.objects.create(name="Woodstock concert", group=band_hype) # FK lookup. concert_model_admin = ConcertAdmin(Concert, custom_site) - concert_model_admin.search_fields = ['group__name', 'name'] + concert_model_admin.search_fields = ["group__name", "name"] # Reverse FK lookup. group_model_admin = GroupAdmin(Group, custom_site) - group_model_admin.search_fields = ['name', 'concert__name', 'members__name'] + group_model_admin.search_fields = ["name", "concert__name", "members__name"] for search_string, result_count in ( - ('Duo Concert', 1), - ('Tiny Desk Concert', 1), - ('Concert', 2), - ('Other Concert', 0), - ('Duo Woodstock', 0), + ("Duo Concert", 1), + ("Tiny Desk Concert", 1), + ("Concert", 2), + ("Other Concert", 0), + ("Duo Woodstock", 0), ): with self.subTest(search_string=search_string): # FK lookup. - request = self.factory.get('/concert/', data={SEARCH_VAR: search_string}) + request = self.factory.get( + "/concert/", data={SEARCH_VAR: search_string} + ) request.user = self.superuser - concert_changelist = concert_model_admin.get_changelist_instance(request) + concert_changelist = concert_model_admin.get_changelist_instance( + request + ) self.assertEqual(concert_changelist.queryset.count(), result_count) # Reverse FK lookup. - request = self.factory.get('/group/', data={SEARCH_VAR: search_string}) + request = self.factory.get("/group/", data={SEARCH_VAR: search_string}) request.user = self.superuser group_changelist = group_model_admin.get_changelist_instance(request) self.assertEqual(group_changelist.queryset.count(), result_count) # Many-to-many lookup. for search_string, result_count in ( - ('Finlayson Duo Tiny', 1), - ('Finlayson', 1), - ('Finlayson Hype', 0), - ('Jonathan Finlayson Duo', 1), - ('Mary Jonathan Duo', 0), - ('Oscar Finlayson Duo', 0), + ("Finlayson Duo Tiny", 1), + ("Finlayson", 1), + ("Finlayson Hype", 0), + ("Jonathan Finlayson Duo", 1), + ("Mary Jonathan Duo", 0), + ("Oscar Finlayson Duo", 0), ): with self.subTest(search_string=search_string): - request = self.factory.get('/group/', data={SEARCH_VAR: search_string}) + request = self.factory.get("/group/", data={SEARCH_VAR: search_string}) request.user = self.superuser group_changelist = group_model_admin.get_changelist_instance(request) self.assertEqual(group_changelist.queryset.count(), result_count) def test_pk_in_search_fields(self): - band = Group.objects.create(name='The Hype') - Concert.objects.create(name='Woodstock', group=band) + band = Group.objects.create(name="The Hype") + Concert.objects.create(name="Woodstock", group=band) m = ConcertAdmin(Concert, custom_site) - m.search_fields = ['group__pk'] + m.search_fields = ["group__pk"] - request = self.factory.get('/concert/', data={SEARCH_VAR: band.pk}) + request = self.factory.get("/concert/", data={SEARCH_VAR: band.pk}) request.user = self.superuser cl = m.get_changelist_instance(request) self.assertEqual(cl.queryset.count(), 1) - request = self.factory.get('/concert/', data={SEARCH_VAR: band.pk + 5}) + request = self.factory.get("/concert/", data={SEARCH_VAR: band.pk + 5}) request.user = self.superuser cl = m.get_changelist_instance(request) self.assertEqual(cl.queryset.count(), 0) def test_builtin_lookup_in_search_fields(self): - band = Group.objects.create(name='The Hype') - concert = Concert.objects.create(name='Woodstock', group=band) + band = Group.objects.create(name="The Hype") + concert = Concert.objects.create(name="Woodstock", group=band) m = ConcertAdmin(Concert, custom_site) - m.search_fields = ['name__iexact'] + m.search_fields = ["name__iexact"] - request = self.factory.get('/', data={SEARCH_VAR: 'woodstock'}) + request = self.factory.get("/", data={SEARCH_VAR: "woodstock"}) request.user = self.superuser cl = m.get_changelist_instance(request) self.assertCountEqual(cl.queryset, [concert]) - request = self.factory.get('/', data={SEARCH_VAR: 'wood'}) + request = self.factory.get("/", data={SEARCH_VAR: "wood"}) request.user = self.superuser cl = m.get_changelist_instance(request) self.assertCountEqual(cl.queryset, []) def test_custom_lookup_in_search_fields(self): - band = Group.objects.create(name='The Hype') - concert = Concert.objects.create(name='Woodstock', group=band) + band = Group.objects.create(name="The Hype") + concert = Concert.objects.create(name="Woodstock", group=band) m = ConcertAdmin(Concert, custom_site) - m.search_fields = ['group__name__cc'] - with register_lookup(Field, Contains, lookup_name='cc'): - request = self.factory.get('/', data={SEARCH_VAR: 'Hype'}) + m.search_fields = ["group__name__cc"] + with register_lookup(Field, Contains, lookup_name="cc"): + request = self.factory.get("/", data={SEARCH_VAR: "Hype"}) request.user = self.superuser cl = m.get_changelist_instance(request) self.assertCountEqual(cl.queryset, [concert]) - request = self.factory.get('/', data={SEARCH_VAR: 'Woodstock'}) + request = self.factory.get("/", data={SEARCH_VAR: "Woodstock"}) request.user = self.superuser cl = m.get_changelist_instance(request) self.assertCountEqual(cl.queryset, []) def test_spanning_relations_with_custom_lookup_in_search_fields(self): - hype = Group.objects.create(name='The Hype') - concert = Concert.objects.create(name='Woodstock', group=hype) - vox = Musician.objects.create(name='Vox', age=20) + hype = Group.objects.create(name="The Hype") + concert = Concert.objects.create(name="Woodstock", group=hype) + vox = Musician.objects.create(name="Vox", age=20) Membership.objects.create(music=vox, group=hype) # Register a custom lookup on IntegerField to ensure that field # traversing logic in ModelAdmin.get_search_results() works. - with register_lookup(IntegerField, Exact, lookup_name='exactly'): + with register_lookup(IntegerField, Exact, lookup_name="exactly"): m = ConcertAdmin(Concert, custom_site) - m.search_fields = ['group__members__age__exactly'] + m.search_fields = ["group__members__age__exactly"] - request = self.factory.get('/', data={SEARCH_VAR: '20'}) + request = self.factory.get("/", data={SEARCH_VAR: "20"}) request.user = self.superuser cl = m.get_changelist_instance(request) self.assertCountEqual(cl.queryset, [concert]) - request = self.factory.get('/', data={SEARCH_VAR: '21'}) + request = self.factory.get("/", data={SEARCH_VAR: "21"}) request.user = self.superuser cl = m.get_changelist_instance(request) self.assertCountEqual(cl.queryset, []) def test_custom_lookup_with_pk_shortcut(self): - self.assertEqual(CharPK._meta.pk.name, 'char_pk') # Not equal to 'pk'. + self.assertEqual(CharPK._meta.pk.name, "char_pk") # Not equal to 'pk'. m = admin.ModelAdmin(CustomIdUser, custom_site) - abc = CharPK.objects.create(char_pk='abc') - abcd = CharPK.objects.create(char_pk='abcd') + abc = CharPK.objects.create(char_pk="abc") + abcd = CharPK.objects.create(char_pk="abcd") m = admin.ModelAdmin(CharPK, custom_site) - m.search_fields = ['pk__exact'] + m.search_fields = ["pk__exact"] - request = self.factory.get('/', data={SEARCH_VAR: 'abc'}) + request = self.factory.get("/", data={SEARCH_VAR: "abc"}) request.user = self.superuser cl = m.get_changelist_instance(request) self.assertCountEqual(cl.queryset, [abc]) - request = self.factory.get('/', data={SEARCH_VAR: 'abcd'}) + request = self.factory.get("/", data={SEARCH_VAR: "abcd"}) request.user = self.superuser cl = m.get_changelist_instance(request) self.assertCountEqual(cl.queryset, [abcd]) @@ -697,29 +772,29 @@ class ChangeListTests(TestCase): the changelist's query shouldn't have Exists(). """ m = BandAdmin(Band, custom_site) - for lookup_params in ({}, {'name': 'test'}): - request = self.factory.get('/band/', lookup_params) + for lookup_params in ({}, {"name": "test"}): + request = self.factory.get("/band/", lookup_params) request.user = self.superuser cl = m.get_changelist_instance(request) - self.assertNotIn(' EXISTS', str(cl.queryset.query)) + self.assertNotIn(" EXISTS", str(cl.queryset.query)) # A ManyToManyField in params does have Exists() applied. - request = self.factory.get('/band/', {'genres': '0'}) + request = self.factory.get("/band/", {"genres": "0"}) request.user = self.superuser cl = m.get_changelist_instance(request) - self.assertIn(' EXISTS', str(cl.queryset.query)) + self.assertIn(" EXISTS", str(cl.queryset.query)) def test_pagination(self): """ Regression tests for #12893: Pagination in admins changelist doesn't use queryset set by modeladmin. """ - parent = Parent.objects.create(name='anything') + parent = Parent.objects.create(name="anything") for i in range(1, 31): - Child.objects.create(name='name %s' % i, parent=parent) - Child.objects.create(name='filtered %s' % i, parent=parent) + Child.objects.create(name="name %s" % i, parent=parent) + Child.objects.create(name="filtered %s" % i, parent=parent) - request = self.factory.get('/child/') + request = self.factory.get("/child/") request.user = self.superuser # Test default queryset @@ -743,7 +818,7 @@ class ChangeListTests(TestCase): """ self.client.force_login(self.superuser) event = Event.objects.create(date=datetime.date.today()) - response = self.client.get(reverse('admin:admin_changelist_event_changelist')) + response = self.client.get(reverse("admin:admin_changelist_event_changelist")) self.assertContains(response, formats.localize(event.date)) self.assertNotContains(response, str(event.date)) @@ -751,52 +826,52 @@ class ChangeListTests(TestCase): """ Regression tests for #14206: dynamic list_display support. """ - parent = Parent.objects.create(name='parent') + parent = Parent.objects.create(name="parent") for i in range(10): - Child.objects.create(name='child %s' % i, parent=parent) + Child.objects.create(name="child %s" % i, parent=parent) - user_noparents = self._create_superuser('noparents') - user_parents = self._create_superuser('parents') + user_noparents = self._create_superuser("noparents") + user_parents = self._create_superuser("parents") # Test with user 'noparents' m = custom_site._registry[Child] - request = self._mocked_authenticated_request('/child/', user_noparents) + request = self._mocked_authenticated_request("/child/", user_noparents) response = m.changelist_view(request) - self.assertNotContains(response, 'Parent object') + self.assertNotContains(response, "Parent object") list_display = m.get_list_display(request) list_display_links = m.get_list_display_links(request, list_display) - self.assertEqual(list_display, ['name', 'age']) - self.assertEqual(list_display_links, ['name']) + self.assertEqual(list_display, ["name", "age"]) + self.assertEqual(list_display_links, ["name"]) # Test with user 'parents' m = DynamicListDisplayChildAdmin(Child, custom_site) - request = self._mocked_authenticated_request('/child/', user_parents) + request = self._mocked_authenticated_request("/child/", user_parents) response = m.changelist_view(request) - self.assertContains(response, 'Parent object') + self.assertContains(response, "Parent object") custom_site.unregister(Child) list_display = m.get_list_display(request) list_display_links = m.get_list_display_links(request, list_display) - self.assertEqual(list_display, ('parent', 'name', 'age')) - self.assertEqual(list_display_links, ['parent']) + self.assertEqual(list_display, ("parent", "name", "age")) + self.assertEqual(list_display_links, ["parent"]) # Test default implementation custom_site.register(Child, ChildAdmin) m = custom_site._registry[Child] - request = self._mocked_authenticated_request('/child/', user_noparents) + request = self._mocked_authenticated_request("/child/", user_noparents) response = m.changelist_view(request) - self.assertContains(response, 'Parent object') + self.assertContains(response, "Parent object") def test_show_all(self): - parent = Parent.objects.create(name='anything') + parent = Parent.objects.create(name="anything") for i in range(1, 31): - Child.objects.create(name='name %s' % i, parent=parent) - Child.objects.create(name='filtered %s' % i, parent=parent) + Child.objects.create(name="name %s" % i, parent=parent) + Child.objects.create(name="filtered %s" % i, parent=parent) # Add "show all" parameter to request - request = self.factory.get('/child/', data={ALL_VAR: ''}) + request = self.factory.get("/child/", data={ALL_VAR: ""}) request.user = self.superuser # Test valid "show all" request (number of total objects is under max) @@ -820,52 +895,52 @@ class ChangeListTests(TestCase): """ Regression tests for #16257: dynamic list_display_links support. """ - parent = Parent.objects.create(name='parent') + parent = Parent.objects.create(name="parent") for i in range(1, 10): - Child.objects.create(id=i, name='child %s' % i, parent=parent, age=i) + Child.objects.create(id=i, name="child %s" % i, parent=parent, age=i) m = DynamicListDisplayLinksChildAdmin(Child, custom_site) - superuser = self._create_superuser('superuser') - request = self._mocked_authenticated_request('/child/', superuser) + superuser = self._create_superuser("superuser") + request = self._mocked_authenticated_request("/child/", superuser) response = m.changelist_view(request) for i in range(1, 10): - link = reverse('admin:admin_changelist_child_change', args=(i,)) + link = reverse("admin:admin_changelist_child_change", args=(i,)) self.assertContains(response, '<a href="%s">%s</a>' % (link, i)) list_display = m.get_list_display(request) list_display_links = m.get_list_display_links(request, list_display) - self.assertEqual(list_display, ('parent', 'name', 'age')) - self.assertEqual(list_display_links, ['age']) + self.assertEqual(list_display, ("parent", "name", "age")) + self.assertEqual(list_display_links, ["age"]) def test_no_list_display_links(self): """#15185 -- Allow no links from the 'change list' view grid.""" - p = Parent.objects.create(name='parent') + p = Parent.objects.create(name="parent") m = NoListDisplayLinksParentAdmin(Parent, custom_site) - superuser = self._create_superuser('superuser') - request = self._mocked_authenticated_request('/parent/', superuser) + superuser = self._create_superuser("superuser") + request = self._mocked_authenticated_request("/parent/", superuser) response = m.changelist_view(request) - link = reverse('admin:admin_changelist_parent_change', args=(p.pk,)) + link = reverse("admin:admin_changelist_parent_change", args=(p.pk,)) self.assertNotContains(response, '<a href="%s">' % link) def test_clear_all_filters_link(self): self.client.force_login(self.superuser) - url = reverse('admin:auth_user_changelist') + url = reverse("admin:auth_user_changelist") response = self.client.get(url) - self.assertNotContains(response, '✖ Clear all filters') + self.assertNotContains(response, "✖ Clear all filters") link = '<a href="%s">✖ Clear all filters</a>' for data, href in ( - ({'is_staff__exact': '0'}, '?'), + ({"is_staff__exact": "0"}, "?"), ( - {'is_staff__exact': '0', 'username__startswith': 'test'}, - '?username__startswith=test', + {"is_staff__exact": "0", "username__startswith": "test"}, + "?username__startswith=test", ), ( - {'is_staff__exact': '0', SEARCH_VAR: 'test'}, - '?%s=test' % SEARCH_VAR, + {"is_staff__exact": "0", SEARCH_VAR: "test"}, + "?%s=test" % SEARCH_VAR, ), ( - {'is_staff__exact': '0', IS_POPUP_VAR: 'id'}, - '?%s=id' % IS_POPUP_VAR, + {"is_staff__exact": "0", IS_POPUP_VAR: "id"}, + "?%s=id" % IS_POPUP_VAR, ), ): with self.subTest(data=data): @@ -874,19 +949,19 @@ class ChangeListTests(TestCase): def test_clear_all_filters_link_callable_filter(self): self.client.force_login(self.superuser) - url = reverse('admin:admin_changelist_band_changelist') + url = reverse("admin:admin_changelist_band_changelist") response = self.client.get(url) - self.assertNotContains(response, '✖ Clear all filters') + self.assertNotContains(response, "✖ Clear all filters") link = '<a href="%s">✖ Clear all filters</a>' for data, href in ( - ({'nr_of_members_partition': '5'}, '?'), + ({"nr_of_members_partition": "5"}, "?"), ( - {'nr_of_members_partition': 'more', 'name__startswith': 'test'}, - '?name__startswith=test', + {"nr_of_members_partition": "more", "name__startswith": "test"}, + "?name__startswith=test", ), ( - {'nr_of_members_partition': '5', IS_POPUP_VAR: 'id'}, - '?%s=id' % IS_POPUP_VAR, + {"nr_of_members_partition": "5", IS_POPUP_VAR: "id"}, + "?%s=id" % IS_POPUP_VAR, ), ): with self.subTest(data=data): @@ -895,28 +970,28 @@ class ChangeListTests(TestCase): def test_no_clear_all_filters_link(self): self.client.force_login(self.superuser) - url = reverse('admin:auth_user_changelist') - link = '>✖ Clear all filters</a>' + url = reverse("admin:auth_user_changelist") + link = ">✖ Clear all filters</a>" for data in ( - {SEARCH_VAR: 'test'}, - {ORDER_VAR: '-1'}, - {TO_FIELD_VAR: 'id'}, - {PAGE_VAR: '1'}, - {IS_POPUP_VAR: '1'}, - {'username__startswith': 'test'}, + {SEARCH_VAR: "test"}, + {ORDER_VAR: "-1"}, + {TO_FIELD_VAR: "id"}, + {PAGE_VAR: "1"}, + {IS_POPUP_VAR: "1"}, + {"username__startswith": "test"}, ): with self.subTest(data=data): response = self.client.get(url, data=data) self.assertNotContains(response, link) def test_tuple_list_display(self): - swallow = Swallow.objects.create(origin='Africa', load='12.34', speed='22.2') - swallow2 = Swallow.objects.create(origin='Africa', load='12.34', speed='22.2') + swallow = Swallow.objects.create(origin="Africa", load="12.34", speed="22.2") + swallow2 = Swallow.objects.create(origin="Africa", load="12.34", speed="22.2") swallow_o2o = SwallowOneToOne.objects.create(swallow=swallow2) model_admin = SwallowAdmin(Swallow, custom_site) - superuser = self._create_superuser('superuser') - request = self._mocked_authenticated_request('/swallow/', superuser) + superuser = self._create_superuser("superuser") + request = self._mocked_authenticated_request("/swallow/", superuser) response = model_admin.changelist_view(request) # just want to ensure it doesn't blow up during rendering self.assertContains(response, str(swallow.origin)) @@ -924,7 +999,9 @@ class ChangeListTests(TestCase): self.assertContains(response, str(swallow.speed)) # Reverse one-to-one relations should work. self.assertContains(response, '<td class="field-swallowonetoone">-</td>') - self.assertContains(response, '<td class="field-swallowonetoone">%s</td>' % swallow_o2o) + self.assertContains( + response, '<td class="field-swallowonetoone">%s</td>' % swallow_o2o + ) def test_multiuser_edit(self): """ @@ -945,150 +1022,152 @@ class ChangeListTests(TestCase): # Setup the test to reflect the DB state after step 2 where User2 has # edited the first swallow object's speed from '4' to '1'. - a = Swallow.objects.create(origin='Swallow A', load=4, speed=1) - b = Swallow.objects.create(origin='Swallow B', load=2, speed=2) - c = Swallow.objects.create(origin='Swallow C', load=5, speed=5) - d = Swallow.objects.create(origin='Swallow D', load=9, speed=9) + a = Swallow.objects.create(origin="Swallow A", load=4, speed=1) + b = Swallow.objects.create(origin="Swallow B", load=2, speed=2) + c = Swallow.objects.create(origin="Swallow C", load=5, speed=5) + d = Swallow.objects.create(origin="Swallow D", load=9, speed=9) - superuser = self._create_superuser('superuser') + superuser = self._create_superuser("superuser") self.client.force_login(superuser) - changelist_url = reverse('admin:admin_changelist_swallow_changelist') + changelist_url = reverse("admin:admin_changelist_swallow_changelist") # Send the POST from User1 for step 3. It's still using the changelist # ordering from before User2's edits in step 2. data = { - 'form-TOTAL_FORMS': '3', - 'form-INITIAL_FORMS': '3', - 'form-MIN_NUM_FORMS': '0', - 'form-MAX_NUM_FORMS': '1000', - 'form-0-uuid': str(d.pk), - 'form-1-uuid': str(c.pk), - 'form-2-uuid': str(a.pk), - 'form-0-load': '9.0', - 'form-0-speed': '9.0', - 'form-1-load': '5.0', - 'form-1-speed': '5.0', - 'form-2-load': '5.0', - 'form-2-speed': '4.0', - '_save': 'Save', + "form-TOTAL_FORMS": "3", + "form-INITIAL_FORMS": "3", + "form-MIN_NUM_FORMS": "0", + "form-MAX_NUM_FORMS": "1000", + "form-0-uuid": str(d.pk), + "form-1-uuid": str(c.pk), + "form-2-uuid": str(a.pk), + "form-0-load": "9.0", + "form-0-speed": "9.0", + "form-1-load": "5.0", + "form-1-speed": "5.0", + "form-2-load": "5.0", + "form-2-speed": "4.0", + "_save": "Save", } - response = self.client.post(changelist_url, data, follow=True, extra={'o': '-2'}) + response = self.client.post( + changelist_url, data, follow=True, extra={"o": "-2"} + ) # The object User1 edited in step 3 is displayed on the changelist and # has the correct edits applied. - self.assertContains(response, '1 swallow was changed successfully.') + self.assertContains(response, "1 swallow was changed successfully.") self.assertContains(response, a.origin) a.refresh_from_db() - self.assertEqual(a.load, float(data['form-2-load'])) - self.assertEqual(a.speed, float(data['form-2-speed'])) + self.assertEqual(a.load, float(data["form-2-load"])) + self.assertEqual(a.speed, float(data["form-2-speed"])) b.refresh_from_db() self.assertEqual(b.load, 2) self.assertEqual(b.speed, 2) c.refresh_from_db() - self.assertEqual(c.load, float(data['form-1-load'])) - self.assertEqual(c.speed, float(data['form-1-speed'])) + self.assertEqual(c.load, float(data["form-1-load"])) + self.assertEqual(c.speed, float(data["form-1-speed"])) d.refresh_from_db() - self.assertEqual(d.load, float(data['form-0-load'])) - self.assertEqual(d.speed, float(data['form-0-speed'])) + self.assertEqual(d.load, float(data["form-0-load"])) + self.assertEqual(d.speed, float(data["form-0-speed"])) # No new swallows were created. self.assertEqual(len(Swallow.objects.all()), 4) def test_get_edited_object_ids(self): - a = Swallow.objects.create(origin='Swallow A', load=4, speed=1) - b = Swallow.objects.create(origin='Swallow B', load=2, speed=2) - c = Swallow.objects.create(origin='Swallow C', load=5, speed=5) - superuser = self._create_superuser('superuser') + a = Swallow.objects.create(origin="Swallow A", load=4, speed=1) + b = Swallow.objects.create(origin="Swallow B", load=2, speed=2) + c = Swallow.objects.create(origin="Swallow C", load=5, speed=5) + superuser = self._create_superuser("superuser") self.client.force_login(superuser) - changelist_url = reverse('admin:admin_changelist_swallow_changelist') + changelist_url = reverse("admin:admin_changelist_swallow_changelist") m = SwallowAdmin(Swallow, custom_site) data = { - 'form-TOTAL_FORMS': '3', - 'form-INITIAL_FORMS': '3', - 'form-MIN_NUM_FORMS': '0', - 'form-MAX_NUM_FORMS': '1000', - 'form-0-uuid': str(a.pk), - 'form-1-uuid': str(b.pk), - 'form-2-uuid': str(c.pk), - 'form-0-load': '9.0', - 'form-0-speed': '9.0', - 'form-1-load': '5.0', - 'form-1-speed': '5.0', - 'form-2-load': '5.0', - 'form-2-speed': '4.0', - '_save': 'Save', + "form-TOTAL_FORMS": "3", + "form-INITIAL_FORMS": "3", + "form-MIN_NUM_FORMS": "0", + "form-MAX_NUM_FORMS": "1000", + "form-0-uuid": str(a.pk), + "form-1-uuid": str(b.pk), + "form-2-uuid": str(c.pk), + "form-0-load": "9.0", + "form-0-speed": "9.0", + "form-1-load": "5.0", + "form-1-speed": "5.0", + "form-2-load": "5.0", + "form-2-speed": "4.0", + "_save": "Save", } request = self.factory.post(changelist_url, data=data) - pks = m._get_edited_object_pks(request, prefix='form') + pks = m._get_edited_object_pks(request, prefix="form") self.assertEqual(sorted(pks), sorted([str(a.pk), str(b.pk), str(c.pk)])) def test_get_list_editable_queryset(self): - a = Swallow.objects.create(origin='Swallow A', load=4, speed=1) - Swallow.objects.create(origin='Swallow B', load=2, speed=2) + a = Swallow.objects.create(origin="Swallow A", load=4, speed=1) + Swallow.objects.create(origin="Swallow B", load=2, speed=2) data = { - 'form-TOTAL_FORMS': '2', - 'form-INITIAL_FORMS': '2', - 'form-MIN_NUM_FORMS': '0', - 'form-MAX_NUM_FORMS': '1000', - 'form-0-uuid': str(a.pk), - 'form-0-load': '10', - '_save': 'Save', + "form-TOTAL_FORMS": "2", + "form-INITIAL_FORMS": "2", + "form-MIN_NUM_FORMS": "0", + "form-MAX_NUM_FORMS": "1000", + "form-0-uuid": str(a.pk), + "form-0-load": "10", + "_save": "Save", } - superuser = self._create_superuser('superuser') + superuser = self._create_superuser("superuser") self.client.force_login(superuser) - changelist_url = reverse('admin:admin_changelist_swallow_changelist') + changelist_url = reverse("admin:admin_changelist_swallow_changelist") m = SwallowAdmin(Swallow, custom_site) request = self.factory.post(changelist_url, data=data) - queryset = m._get_list_editable_queryset(request, prefix='form') + queryset = m._get_list_editable_queryset(request, prefix="form") self.assertEqual(queryset.count(), 1) - data['form-0-uuid'] = 'INVALD_PRIMARY_KEY' + data["form-0-uuid"] = "INVALD_PRIMARY_KEY" # The unfiltered queryset is returned if there's invalid data. request = self.factory.post(changelist_url, data=data) - queryset = m._get_list_editable_queryset(request, prefix='form') + queryset = m._get_list_editable_queryset(request, prefix="form") self.assertEqual(queryset.count(), 2) def test_get_list_editable_queryset_with_regex_chars_in_prefix(self): - a = Swallow.objects.create(origin='Swallow A', load=4, speed=1) - Swallow.objects.create(origin='Swallow B', load=2, speed=2) + a = Swallow.objects.create(origin="Swallow A", load=4, speed=1) + Swallow.objects.create(origin="Swallow B", load=2, speed=2) data = { - 'form$-TOTAL_FORMS': '2', - 'form$-INITIAL_FORMS': '2', - 'form$-MIN_NUM_FORMS': '0', - 'form$-MAX_NUM_FORMS': '1000', - 'form$-0-uuid': str(a.pk), - 'form$-0-load': '10', - '_save': 'Save', + "form$-TOTAL_FORMS": "2", + "form$-INITIAL_FORMS": "2", + "form$-MIN_NUM_FORMS": "0", + "form$-MAX_NUM_FORMS": "1000", + "form$-0-uuid": str(a.pk), + "form$-0-load": "10", + "_save": "Save", } - superuser = self._create_superuser('superuser') + superuser = self._create_superuser("superuser") self.client.force_login(superuser) - changelist_url = reverse('admin:admin_changelist_swallow_changelist') + changelist_url = reverse("admin:admin_changelist_swallow_changelist") m = SwallowAdmin(Swallow, custom_site) request = self.factory.post(changelist_url, data=data) - queryset = m._get_list_editable_queryset(request, prefix='form$') + queryset = m._get_list_editable_queryset(request, prefix="form$") self.assertEqual(queryset.count(), 1) def test_changelist_view_list_editable_changed_objects_uses_filter(self): """list_editable edits use a filtered queryset to limit memory usage.""" - a = Swallow.objects.create(origin='Swallow A', load=4, speed=1) - Swallow.objects.create(origin='Swallow B', load=2, speed=2) + a = Swallow.objects.create(origin="Swallow A", load=4, speed=1) + Swallow.objects.create(origin="Swallow B", load=2, speed=2) data = { - 'form-TOTAL_FORMS': '2', - 'form-INITIAL_FORMS': '2', - 'form-MIN_NUM_FORMS': '0', - 'form-MAX_NUM_FORMS': '1000', - 'form-0-uuid': str(a.pk), - 'form-0-load': '10', - '_save': 'Save', + "form-TOTAL_FORMS": "2", + "form-INITIAL_FORMS": "2", + "form-MIN_NUM_FORMS": "0", + "form-MAX_NUM_FORMS": "1000", + "form-0-uuid": str(a.pk), + "form-0-load": "10", + "_save": "Save", } - superuser = self._create_superuser('superuser') + superuser = self._create_superuser("superuser") self.client.force_login(superuser) - changelist_url = reverse('admin:admin_changelist_swallow_changelist') + changelist_url = reverse("admin:admin_changelist_swallow_changelist") with CaptureQueriesContext(connection) as context: response = self.client.post(changelist_url, data=data) self.assertEqual(response.status_code, 200) - self.assertIn('WHERE', context.captured_queries[4]['sql']) - self.assertIn('IN', context.captured_queries[4]['sql']) + self.assertIn("WHERE", context.captured_queries[4]["sql"]) + self.assertIn("IN", context.captured_queries[4]["sql"]) # Check only the first few characters since the UUID may have dashes. - self.assertIn(str(a.pk)[:8], context.captured_queries[4]['sql']) + self.assertIn(str(a.pk)[:8], context.captured_queries[4]["sql"]) def test_deterministic_order_for_unordered_model(self): """ @@ -1096,7 +1175,7 @@ class ChangeListTests(TestCase): guarantee a deterministic order, even when the model doesn't have any default ordering defined (#17198). """ - superuser = self._create_superuser('superuser') + superuser = self._create_superuser("superuser") for counter in range(1, 51): UnorderedObject.objects.create(id=counter, bool=True) @@ -1109,9 +1188,11 @@ class ChangeListTests(TestCase): model_admin = UnorderedObjectAdmin(UnorderedObject, custom_site) counter = 0 if ascending else 51 for page in range(1, 6): - request = self._mocked_authenticated_request('/unorderedobject/?p=%s' % page, superuser) + request = self._mocked_authenticated_request( + "/unorderedobject/?p=%s" % page, superuser + ) response = model_admin.changelist_view(request) - for result in response.context_data['cl'].result_list: + for result in response.context_data["cl"].result_list: counter += 1 if ascending else -1 self.assertEqual(result.id, counter) custom_site.unregister(UnorderedObject) @@ -1121,17 +1202,17 @@ class ChangeListTests(TestCase): # When an order field is defined but multiple records have the same # value for that field, make sure everything gets ordered by -pk as well. - UnorderedObjectAdmin.ordering = ['bool'] + UnorderedObjectAdmin.ordering = ["bool"] check_results_order() # When order fields are defined, including the pk itself, use them. - UnorderedObjectAdmin.ordering = ['bool', '-pk'] + UnorderedObjectAdmin.ordering = ["bool", "-pk"] check_results_order() - UnorderedObjectAdmin.ordering = ['bool', 'pk'] + UnorderedObjectAdmin.ordering = ["bool", "pk"] check_results_order(ascending=True) - UnorderedObjectAdmin.ordering = ['-id', 'bool'] + UnorderedObjectAdmin.ordering = ["-id", "bool"] check_results_order() - UnorderedObjectAdmin.ordering = ['id', 'bool'] + UnorderedObjectAdmin.ordering = ["id", "bool"] check_results_order(ascending=True) def test_deterministic_order_for_model_ordered_by_its_manager(self): @@ -1140,7 +1221,7 @@ class ChangeListTests(TestCase): guarantee a deterministic order, even when the model has a manager that defines a default ordering (#17198). """ - superuser = self._create_superuser('superuser') + superuser = self._create_superuser("superuser") for counter in range(1, 51): OrderedObject.objects.create(id=counter, bool=True, number=counter) @@ -1153,9 +1234,11 @@ class ChangeListTests(TestCase): model_admin = OrderedObjectAdmin(OrderedObject, custom_site) counter = 0 if ascending else 51 for page in range(1, 6): - request = self._mocked_authenticated_request('/orderedobject/?p=%s' % page, superuser) + request = self._mocked_authenticated_request( + "/orderedobject/?p=%s" % page, superuser + ) response = model_admin.changelist_view(request) - for result in response.context_data['cl'].result_list: + for result in response.context_data["cl"].result_list: counter += 1 if ascending else -1 self.assertEqual(result.id, counter) custom_site.unregister(OrderedObject) @@ -1165,26 +1248,26 @@ class ChangeListTests(TestCase): # When an order field is defined but multiple records have the same # value for that field, make sure everything gets ordered by -pk as well. - OrderedObjectAdmin.ordering = ['bool'] + OrderedObjectAdmin.ordering = ["bool"] check_results_order() # When order fields are defined, including the pk itself, use them. - OrderedObjectAdmin.ordering = ['bool', '-pk'] + OrderedObjectAdmin.ordering = ["bool", "-pk"] check_results_order() - OrderedObjectAdmin.ordering = ['bool', 'pk'] + OrderedObjectAdmin.ordering = ["bool", "pk"] check_results_order(ascending=True) - OrderedObjectAdmin.ordering = ['-id', 'bool'] + OrderedObjectAdmin.ordering = ["-id", "bool"] check_results_order() - OrderedObjectAdmin.ordering = ['id', 'bool'] + OrderedObjectAdmin.ordering = ["id", "bool"] check_results_order(ascending=True) - @isolate_apps('admin_changelist') + @isolate_apps("admin_changelist") def test_total_ordering_optimization(self): class Related(models.Model): unique_field = models.BooleanField(unique=True) class Meta: - ordering = ('unique_field',) + ordering = ("unique_field",) class Model(models.Model): unique_field = models.BooleanField(unique=True) @@ -1198,64 +1281,69 @@ class ChangeListTests(TestCase): class Meta: unique_together = { - ('field', 'other_field'), - ('field', 'null_field'), - ('related', 'other_related_id'), + ("field", "other_field"), + ("field", "null_field"), + ("related", "other_related_id"), } class ModelAdmin(admin.ModelAdmin): def get_queryset(self, request): return Model.objects.none() - request = self._mocked_authenticated_request('/', self.superuser) - site = admin.AdminSite(name='admin') + request = self._mocked_authenticated_request("/", self.superuser) + site = admin.AdminSite(name="admin") model_admin = ModelAdmin(Model, site) change_list = model_admin.get_changelist_instance(request) tests = ( - ([], ['-pk']), + ([], ["-pk"]), # Unique non-nullable field. - (['unique_field'], ['unique_field']), - (['-unique_field'], ['-unique_field']), + (["unique_field"], ["unique_field"]), + (["-unique_field"], ["-unique_field"]), # Unique nullable field. - (['unique_nullable_field'], ['unique_nullable_field', '-pk']), + (["unique_nullable_field"], ["unique_nullable_field", "-pk"]), # Field. - (['field'], ['field', '-pk']), + (["field"], ["field", "-pk"]), # Related field introspection is not implemented. - (['related__unique_field'], ['related__unique_field', '-pk']), + (["related__unique_field"], ["related__unique_field", "-pk"]), # Related attname unique. - (['related_unique_id'], ['related_unique_id']), + (["related_unique_id"], ["related_unique_id"]), # Related ordering introspection is not implemented. - (['related_unique'], ['related_unique', '-pk']), + (["related_unique"], ["related_unique", "-pk"]), # Composite unique. - (['field', '-other_field'], ['field', '-other_field']), + (["field", "-other_field"], ["field", "-other_field"]), # Composite unique nullable. - (['-field', 'null_field'], ['-field', 'null_field', '-pk']), + (["-field", "null_field"], ["-field", "null_field", "-pk"]), # Composite unique and nullable. - (['-field', 'null_field', 'other_field'], ['-field', 'null_field', 'other_field']), + ( + ["-field", "null_field", "other_field"], + ["-field", "null_field", "other_field"], + ), # Composite unique attnames. - (['related_id', '-other_related_id'], ['related_id', '-other_related_id']), + (["related_id", "-other_related_id"], ["related_id", "-other_related_id"]), # Composite unique names. - (['related', '-other_related_id'], ['related', '-other_related_id', '-pk']), + (["related", "-other_related_id"], ["related", "-other_related_id", "-pk"]), ) # F() objects composite unique. - total_ordering = [F('field'), F('other_field').desc(nulls_last=True)] + total_ordering = [F("field"), F("other_field").desc(nulls_last=True)] # F() objects composite unique nullable. - non_total_ordering = [F('field'), F('null_field').desc(nulls_last=True)] + non_total_ordering = [F("field"), F("null_field").desc(nulls_last=True)] tests += ( (total_ordering, total_ordering), - (non_total_ordering, non_total_ordering + ['-pk']), + (non_total_ordering, non_total_ordering + ["-pk"]), ) for ordering, expected in tests: with self.subTest(ordering=ordering): - self.assertEqual(change_list._get_deterministic_ordering(ordering), expected) + self.assertEqual( + change_list._get_deterministic_ordering(ordering), expected + ) - @isolate_apps('admin_changelist') + @isolate_apps("admin_changelist") def test_total_ordering_optimization_meta_constraints(self): class Related(models.Model): unique_field = models.BooleanField(unique=True) class Meta: - ordering = ('unique_field',) + ordering = ("unique_field",) class Model(models.Model): field_1 = models.BooleanField() @@ -1274,28 +1362,28 @@ class ChangeListTests(TestCase): class Meta: constraints = [ *[ - models.UniqueConstraint(fields=fields, name=''.join(fields)) + models.UniqueConstraint(fields=fields, name="".join(fields)) for fields in ( - ['field_1'], - ['nullable_1'], - ['related_1'], - ['related_2_id'], - ['field_2', 'field_3'], - ['field_2', 'nullable_2'], - ['field_2', 'related_3'], - ['field_3', 'related_4_id'], + ["field_1"], + ["nullable_1"], + ["related_1"], + ["related_2_id"], + ["field_2", "field_3"], + ["field_2", "nullable_2"], + ["field_2", "related_3"], + ["field_3", "related_4_id"], ) ], - models.CheckConstraint(check=models.Q(id__gt=0), name='foo'), + models.CheckConstraint(check=models.Q(id__gt=0), name="foo"), models.UniqueConstraint( - fields=['field_5'], + fields=["field_5"], condition=models.Q(id__gt=10), - name='total_ordering_1', + name="total_ordering_1", ), models.UniqueConstraint( - fields=['field_6'], + fields=["field_6"], condition=models.Q(), - name='total_ordering', + name="total_ordering", ), ] @@ -1303,73 +1391,77 @@ class ChangeListTests(TestCase): def get_queryset(self, request): return Model.objects.none() - request = self._mocked_authenticated_request('/', self.superuser) - site = admin.AdminSite(name='admin') + request = self._mocked_authenticated_request("/", self.superuser) + site = admin.AdminSite(name="admin") model_admin = ModelAdmin(Model, site) change_list = model_admin.get_changelist_instance(request) tests = ( # Unique non-nullable field. - (['field_1'], ['field_1']), + (["field_1"], ["field_1"]), # Unique nullable field. - (['nullable_1'], ['nullable_1', '-pk']), + (["nullable_1"], ["nullable_1", "-pk"]), # Related attname unique. - (['related_1_id'], ['related_1_id']), - (['related_2_id'], ['related_2_id']), + (["related_1_id"], ["related_1_id"]), + (["related_2_id"], ["related_2_id"]), # Related ordering introspection is not implemented. - (['related_1'], ['related_1', '-pk']), + (["related_1"], ["related_1", "-pk"]), # Composite unique. - (['-field_2', 'field_3'], ['-field_2', 'field_3']), + (["-field_2", "field_3"], ["-field_2", "field_3"]), # Composite unique nullable. - (['field_2', '-nullable_2'], ['field_2', '-nullable_2', '-pk']), + (["field_2", "-nullable_2"], ["field_2", "-nullable_2", "-pk"]), # Composite unique and nullable. ( - ['field_2', '-nullable_2', 'field_3'], - ['field_2', '-nullable_2', 'field_3'], + ["field_2", "-nullable_2", "field_3"], + ["field_2", "-nullable_2", "field_3"], ), # Composite field and related field name. - (['field_2', '-related_3'], ['field_2', '-related_3', '-pk']), - (['field_3', 'related_4'], ['field_3', 'related_4', '-pk']), + (["field_2", "-related_3"], ["field_2", "-related_3", "-pk"]), + (["field_3", "related_4"], ["field_3", "related_4", "-pk"]), # Composite field and related field attname. - (['field_2', 'related_3_id'], ['field_2', 'related_3_id']), - (['field_3', '-related_4_id'], ['field_3', '-related_4_id']), + (["field_2", "related_3_id"], ["field_2", "related_3_id"]), + (["field_3", "-related_4_id"], ["field_3", "-related_4_id"]), # Partial unique constraint is ignored. - (['field_5'], ['field_5', '-pk']), + (["field_5"], ["field_5", "-pk"]), # Unique constraint with an empty condition. - (['field_6'], ['field_6']), + (["field_6"], ["field_6"]), ) for ordering, expected in tests: with self.subTest(ordering=ordering): - self.assertEqual(change_list._get_deterministic_ordering(ordering), expected) + self.assertEqual( + change_list._get_deterministic_ordering(ordering), expected + ) def test_dynamic_list_filter(self): """ Regression tests for ticket #17646: dynamic list_filter support. """ - parent = Parent.objects.create(name='parent') + parent = Parent.objects.create(name="parent") for i in range(10): - Child.objects.create(name='child %s' % i, parent=parent) + Child.objects.create(name="child %s" % i, parent=parent) - user_noparents = self._create_superuser('noparents') - user_parents = self._create_superuser('parents') + user_noparents = self._create_superuser("noparents") + user_parents = self._create_superuser("parents") # Test with user 'noparents' m = DynamicListFilterChildAdmin(Child, custom_site) - request = self._mocked_authenticated_request('/child/', user_noparents) + request = self._mocked_authenticated_request("/child/", user_noparents) response = m.changelist_view(request) - self.assertEqual(response.context_data['cl'].list_filter, ['name', 'age']) + self.assertEqual(response.context_data["cl"].list_filter, ["name", "age"]) # Test with user 'parents' m = DynamicListFilterChildAdmin(Child, custom_site) - request = self._mocked_authenticated_request('/child/', user_parents) + request = self._mocked_authenticated_request("/child/", user_parents) response = m.changelist_view(request) - self.assertEqual(response.context_data['cl'].list_filter, ('parent', 'name', 'age')) + self.assertEqual( + response.context_data["cl"].list_filter, ("parent", "name", "age") + ) def test_dynamic_search_fields(self): - child = self._create_superuser('child') + child = self._create_superuser("child") m = DynamicSearchFieldsChildAdmin(Child, custom_site) - request = self._mocked_authenticated_request('/child/', child) + request = self._mocked_authenticated_request("/child/", child) response = m.changelist_view(request) - self.assertEqual(response.context_data['cl'].search_fields, ('name', 'age')) + self.assertEqual(response.context_data["cl"].search_fields, ("name", "age")) def test_pagination_page_range(self): """ @@ -1378,7 +1470,7 @@ class ChangeListTests(TestCase): """ # instantiating and setting up ChangeList object m = GroupAdmin(Group, custom_site) - request = self.factory.get('/group/') + request = self.factory.get("/group/") request.user = self.superuser cl = m.get_changelist_instance(request) cl.list_per_page = 10 @@ -1401,144 +1493,148 @@ class ChangeListTests(TestCase): # assuming exactly `pages * cl.list_per_page` objects Group.objects.all().delete() for i in range(pages * cl.list_per_page): - Group.objects.create(name='test band') + Group.objects.create(name="test band") # setting page number and calculating page range cl.page_num = number cl.get_results(request) - self.assertEqual(list(pagination(cl)['page_range']), expected) + self.assertEqual(list(pagination(cl)["page_range"]), expected) def test_object_tools_displayed_no_add_permission(self): """ When ModelAdmin.has_add_permission() returns False, the object-tools block is still shown. """ - superuser = self._create_superuser('superuser') + superuser = self._create_superuser("superuser") m = EventAdmin(Event, custom_site) - request = self._mocked_authenticated_request('/event/', superuser) + request = self._mocked_authenticated_request("/event/", superuser) self.assertFalse(m.has_add_permission(request)) response = m.changelist_view(request) self.assertIn('<ul class="object-tools">', response.rendered_content) # The "Add" button inside the object-tools shouldn't appear. - self.assertNotIn('Add ', response.rendered_content) + self.assertNotIn("Add ", response.rendered_content) def test_search_help_text(self): - superuser = self._create_superuser('superuser') + superuser = self._create_superuser("superuser") m = BandAdmin(Band, custom_site) # search_fields without search_help_text. - m.search_fields = ['name'] - request = self._mocked_authenticated_request('/band/', superuser) + m.search_fields = ["name"] + request = self._mocked_authenticated_request("/band/", superuser) response = m.changelist_view(request) - self.assertIsNone(response.context_data['cl'].search_help_text) + self.assertIsNone(response.context_data["cl"].search_help_text) self.assertNotContains(response, '<div class="help">') # search_fields with search_help_text. - m.search_help_text = 'Search help text' - request = self._mocked_authenticated_request('/band/', superuser) + m.search_help_text = "Search help text" + request = self._mocked_authenticated_request("/band/", superuser) response = m.changelist_view(request) - self.assertEqual(response.context_data['cl'].search_help_text, 'Search help text') + self.assertEqual( + response.context_data["cl"].search_help_text, "Search help text" + ) self.assertContains(response, '<div class="help">Search help text</div>') class GetAdminLogTests(TestCase): - def test_custom_user_pk_not_named_id(self): """ {% get_admin_log %} works if the user model's primary key isn't named 'id'. """ - context = Context({'user': CustomIdUser()}) - template = Template('{% load log %}{% get_admin_log 10 as admin_log for_user user %}') + context = Context({"user": CustomIdUser()}) + template = Template( + "{% load log %}{% get_admin_log 10 as admin_log for_user user %}" + ) # This template tag just logs. - self.assertEqual(template.render(context), '') + self.assertEqual(template.render(context), "") def test_no_user(self): """{% get_admin_log %} works without specifying a user.""" - user = User(username='jondoe', password='secret', email='super@example.com') + user = User(username="jondoe", password="secret", email="super@example.com") user.save() ct = ContentType.objects.get_for_model(User) LogEntry.objects.log_action(user.pk, ct.pk, user.pk, repr(user), 1) t = Template( - '{% load log %}' - '{% get_admin_log 100 as admin_log %}' - '{% for entry in admin_log %}' - '{{ entry|safe }}' - '{% endfor %}' + "{% load log %}" + "{% get_admin_log 100 as admin_log %}" + "{% for entry in admin_log %}" + "{{ entry|safe }}" + "{% endfor %}" ) - self.assertEqual(t.render(Context({})), 'Added “<User: jondoe>”.') + self.assertEqual(t.render(Context({})), "Added “<User: jondoe>”.") def test_missing_args(self): msg = "'get_admin_log' statements require two arguments" with self.assertRaisesMessage(TemplateSyntaxError, msg): - Template('{% load log %}{% get_admin_log 10 as %}') + Template("{% load log %}{% get_admin_log 10 as %}") def test_non_integer_limit(self): msg = "First argument to 'get_admin_log' must be an integer" with self.assertRaisesMessage(TemplateSyntaxError, msg): - Template('{% load log %}{% get_admin_log "10" as admin_log for_user user %}') + Template( + '{% load log %}{% get_admin_log "10" as admin_log for_user user %}' + ) def test_without_as(self): msg = "Second argument to 'get_admin_log' must be 'as'" with self.assertRaisesMessage(TemplateSyntaxError, msg): - Template('{% load log %}{% get_admin_log 10 ad admin_log for_user user %}') + Template("{% load log %}{% get_admin_log 10 ad admin_log for_user user %}") def test_without_for_user(self): msg = "Fourth argument to 'get_admin_log' must be 'for_user'" with self.assertRaisesMessage(TemplateSyntaxError, msg): - Template('{% load log %}{% get_admin_log 10 as admin_log foruser user %}') + Template("{% load log %}{% get_admin_log 10 as admin_log foruser user %}") -@override_settings(ROOT_URLCONF='admin_changelist.urls') +@override_settings(ROOT_URLCONF="admin_changelist.urls") class SeleniumTests(AdminSeleniumTestCase): - available_apps = ['admin_changelist'] + AdminSeleniumTestCase.available_apps + available_apps = ["admin_changelist"] + AdminSeleniumTestCase.available_apps def setUp(self): - User.objects.create_superuser(username='super', password='secret', email=None) + User.objects.create_superuser(username="super", password="secret", email=None) def test_add_row_selection(self): """ The status line for selected rows gets updated correctly (#22038). """ from selenium.webdriver.common.by import By - self.admin_login(username='super', password='secret') - self.selenium.get(self.live_server_url + reverse('admin:auth_user_changelist')) - form_id = '#changelist-form' + self.admin_login(username="super", password="secret") + self.selenium.get(self.live_server_url + reverse("admin:auth_user_changelist")) + + form_id = "#changelist-form" # Test amount of rows in the Changelist rows = self.selenium.find_elements( - By.CSS_SELECTOR, - '%s #result_list tbody tr' % form_id + By.CSS_SELECTOR, "%s #result_list tbody tr" % form_id ) self.assertEqual(len(rows), 1) row = rows[0] selection_indicator = self.selenium.find_element( - By.CSS_SELECTOR, - '%s .action-counter' % form_id + By.CSS_SELECTOR, "%s .action-counter" % form_id ) - all_selector = self.selenium.find_element(By.ID, 'action-toggle') + all_selector = self.selenium.find_element(By.ID, "action-toggle") row_selector = self.selenium.find_element( By.CSS_SELECTOR, - '%s #result_list tbody tr:first-child .action-select' % form_id + "%s #result_list tbody tr:first-child .action-select" % form_id, ) # Test current selection self.assertEqual(selection_indicator.text, "0 of 1 selected") - self.assertIs(all_selector.get_property('checked'), False) - self.assertEqual(row.get_attribute('class'), '') + self.assertIs(all_selector.get_property("checked"), False) + self.assertEqual(row.get_attribute("class"), "") # Select a row and check again row_selector.click() self.assertEqual(selection_indicator.text, "1 of 1 selected") - self.assertIs(all_selector.get_property('checked'), True) - self.assertEqual(row.get_attribute('class'), 'selected') + self.assertIs(all_selector.get_property("checked"), True) + self.assertEqual(row.get_attribute("class"), "selected") # Deselect a row and check again row_selector.click() self.assertEqual(selection_indicator.text, "0 of 1 selected") - self.assertIs(all_selector.get_property('checked'), False) - self.assertEqual(row.get_attribute('class'), '') + self.assertIs(all_selector.get_property("checked"), False) + self.assertEqual(row.get_attribute("class"), "") def test_modifier_allows_multiple_section(self): """ @@ -1549,89 +1645,105 @@ class SeleniumTests(AdminSeleniumTestCase): from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys - Parent.objects.bulk_create([Parent(name='parent%d' % i) for i in range(5)]) - self.admin_login(username='super', password='secret') - self.selenium.get(self.live_server_url + reverse('admin:admin_changelist_parent_changelist')) - checkboxes = self.selenium.find_elements(By.CSS_SELECTOR, 'tr input.action-select') + Parent.objects.bulk_create([Parent(name="parent%d" % i) for i in range(5)]) + self.admin_login(username="super", password="secret") + self.selenium.get( + self.live_server_url + reverse("admin:admin_changelist_parent_changelist") + ) + checkboxes = self.selenium.find_elements( + By.CSS_SELECTOR, "tr input.action-select" + ) self.assertEqual(len(checkboxes), 5) for c in checkboxes: - self.assertIs(c.get_property('checked'), False) + self.assertIs(c.get_property("checked"), False) # Check first row. Hold-shift and check next-to-last row. checkboxes[0].click() - ActionChains(self.selenium).key_down(Keys.SHIFT).click(checkboxes[-2]).key_up(Keys.SHIFT).perform() + ActionChains(self.selenium).key_down(Keys.SHIFT).click(checkboxes[-2]).key_up( + Keys.SHIFT + ).perform() for c in checkboxes[:-2]: - self.assertIs(c.get_property('checked'), True) - self.assertIs(checkboxes[-1].get_property('checked'), False) + self.assertIs(c.get_property("checked"), True) + self.assertIs(checkboxes[-1].get_property("checked"), False) def test_select_all_across_pages(self): from selenium.webdriver.common.by import By - Parent.objects.bulk_create([Parent(name='parent%d' % i) for i in range(101)]) - self.admin_login(username='super', password='secret') - self.selenium.get(self.live_server_url + reverse('admin:admin_changelist_parent_changelist')) - selection_indicator = self.selenium.find_element(By.CSS_SELECTOR, '.action-counter') - select_all_indicator = self.selenium.find_element(By.CSS_SELECTOR, '.actions .all') - question = self.selenium.find_element(By.CSS_SELECTOR, '.actions > .question') - clear = self.selenium.find_element(By.CSS_SELECTOR, '.actions > .clear') - select_all = self.selenium.find_element(By.ID, 'action-toggle') - select_across = self.selenium.find_elements(By.NAME, 'select_across') + Parent.objects.bulk_create([Parent(name="parent%d" % i) for i in range(101)]) + self.admin_login(username="super", password="secret") + self.selenium.get( + self.live_server_url + reverse("admin:admin_changelist_parent_changelist") + ) + + selection_indicator = self.selenium.find_element( + By.CSS_SELECTOR, ".action-counter" + ) + select_all_indicator = self.selenium.find_element( + By.CSS_SELECTOR, ".actions .all" + ) + question = self.selenium.find_element(By.CSS_SELECTOR, ".actions > .question") + clear = self.selenium.find_element(By.CSS_SELECTOR, ".actions > .clear") + select_all = self.selenium.find_element(By.ID, "action-toggle") + select_across = self.selenium.find_elements(By.NAME, "select_across") self.assertIs(question.is_displayed(), False) self.assertIs(clear.is_displayed(), False) - self.assertIs(select_all.get_property('checked'), False) + self.assertIs(select_all.get_property("checked"), False) for hidden_input in select_across: - self.assertEqual(hidden_input.get_property('value'), '0') + self.assertEqual(hidden_input.get_property("value"), "0") self.assertIs(selection_indicator.is_displayed(), True) - self.assertEqual(selection_indicator.text, '0 of 100 selected') + self.assertEqual(selection_indicator.text, "0 of 100 selected") self.assertIs(select_all_indicator.is_displayed(), False) select_all.click() self.assertIs(question.is_displayed(), True) self.assertIs(clear.is_displayed(), False) - self.assertIs(select_all.get_property('checked'), True) + self.assertIs(select_all.get_property("checked"), True) for hidden_input in select_across: - self.assertEqual(hidden_input.get_property('value'), '0') + self.assertEqual(hidden_input.get_property("value"), "0") self.assertIs(selection_indicator.is_displayed(), True) - self.assertEqual(selection_indicator.text, '100 of 100 selected') + self.assertEqual(selection_indicator.text, "100 of 100 selected") self.assertIs(select_all_indicator.is_displayed(), False) question.click() self.assertIs(question.is_displayed(), False) self.assertIs(clear.is_displayed(), True) - self.assertIs(select_all.get_property('checked'), True) + self.assertIs(select_all.get_property("checked"), True) for hidden_input in select_across: - self.assertEqual(hidden_input.get_property('value'), '1') + self.assertEqual(hidden_input.get_property("value"), "1") self.assertIs(selection_indicator.is_displayed(), False) self.assertIs(select_all_indicator.is_displayed(), True) clear.click() self.assertIs(question.is_displayed(), False) self.assertIs(clear.is_displayed(), False) - self.assertIs(select_all.get_property('checked'), False) + self.assertIs(select_all.get_property("checked"), False) for hidden_input in select_across: - self.assertEqual(hidden_input.get_property('value'), '0') + self.assertEqual(hidden_input.get_property("value"), "0") self.assertIs(selection_indicator.is_displayed(), True) - self.assertEqual(selection_indicator.text, '0 of 100 selected') + self.assertEqual(selection_indicator.text, "0 of 100 selected") self.assertIs(select_all_indicator.is_displayed(), False) def test_actions_warn_on_pending_edits(self): from selenium.webdriver.common.by import By - Parent.objects.create(name='foo') - self.admin_login(username='super', password='secret') - self.selenium.get(self.live_server_url + reverse('admin:admin_changelist_parent_changelist')) + Parent.objects.create(name="foo") - name_input = self.selenium.find_element(By.ID, 'id_form-0-name') + self.admin_login(username="super", password="secret") + self.selenium.get( + self.live_server_url + reverse("admin:admin_changelist_parent_changelist") + ) + + name_input = self.selenium.find_element(By.ID, "id_form-0-name") name_input.clear() - name_input.send_keys('bar') - self.selenium.find_element(By.ID, 'action-toggle').click() - self.selenium.find_element(By.NAME, 'index').click() # Go + name_input.send_keys("bar") + self.selenium.find_element(By.ID, "action-toggle").click() + self.selenium.find_element(By.NAME, "index").click() # Go alert = self.selenium.switch_to.alert try: self.assertEqual( alert.text, - 'You have unsaved changes on individual editable fields. If you ' - 'run an action, your unsaved changes will be lost.' + "You have unsaved changes on individual editable fields. If you " + "run an action, your unsaved changes will be lost.", ) finally: alert.dismiss() @@ -1640,25 +1752,27 @@ class SeleniumTests(AdminSeleniumTestCase): from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import Select - Parent.objects.create(name='parent') + Parent.objects.create(name="parent") - self.admin_login(username='super', password='secret') - self.selenium.get(self.live_server_url + reverse('admin:admin_changelist_parent_changelist')) + self.admin_login(username="super", password="secret") + self.selenium.get( + self.live_server_url + reverse("admin:admin_changelist_parent_changelist") + ) - name_input = self.selenium.find_element(By.ID, 'id_form-0-name') + name_input = self.selenium.find_element(By.ID, "id_form-0-name") name_input.clear() - name_input.send_keys('other name') - Select( - self.selenium.find_element(By.NAME, 'action') - ).select_by_value('delete_selected') - self.selenium.find_element(By.NAME, '_save').click() + name_input.send_keys("other name") + Select(self.selenium.find_element(By.NAME, "action")).select_by_value( + "delete_selected" + ) + self.selenium.find_element(By.NAME, "_save").click() alert = self.selenium.switch_to.alert try: self.assertEqual( alert.text, - 'You have selected an action, but you haven’t saved your ' - 'changes to individual fields yet. Please click OK to save. ' - 'You’ll need to re-run the action.', + "You have selected an action, but you haven’t saved your " + "changes to individual fields yet. Please click OK to save. " + "You’ll need to re-run the action.", ) finally: alert.dismiss() @@ -1667,22 +1781,24 @@ class SeleniumTests(AdminSeleniumTestCase): from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import Select - Parent.objects.create(name='parent') + Parent.objects.create(name="parent") - self.admin_login(username='super', password='secret') - self.selenium.get(self.live_server_url + reverse('admin:admin_changelist_parent_changelist')) + self.admin_login(username="super", password="secret") + self.selenium.get( + self.live_server_url + reverse("admin:admin_changelist_parent_changelist") + ) - Select( - self.selenium.find_element(By.NAME, 'action') - ).select_by_value('delete_selected') - self.selenium.find_element(By.NAME, '_save').click() + Select(self.selenium.find_element(By.NAME, "action")).select_by_value( + "delete_selected" + ) + self.selenium.find_element(By.NAME, "_save").click() alert = self.selenium.switch_to.alert try: self.assertEqual( alert.text, - 'You have selected an action, and you haven’t made any ' - 'changes on individual fields. You’re probably looking for ' - 'the Go button rather than the Save button.', + "You have selected an action, and you haven’t made any " + "changes on individual fields. You’re probably looking for " + "the Go button rather than the Save button.", ) finally: alert.dismiss() diff --git a/tests/admin_changelist/urls.py b/tests/admin_changelist/urls.py index be569cdca5..ad9b44c9fc 100644 --- a/tests/admin_changelist/urls.py +++ b/tests/admin_changelist/urls.py @@ -3,5 +3,5 @@ from django.urls import path from . import admin urlpatterns = [ - path('admin/', admin.site.urls), + path("admin/", admin.site.urls), ] |