diff options
author | Baptiste Mispelon <bmispelon@gmail.com> | 2019-11-24 23:09:07 +0100 |
---|---|---|
committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2019-11-26 09:19:39 +0100 |
commit | 7873d3757d3075d36cf68771bf4f584ba3386e37 (patch) | |
tree | f06484ef36bf51ee9ac275f37cc3661945389d97 | |
parent | 2af606003a97559cd2c91b2ca0e41b326752303b (diff) | |
download | django-7873d3757d3075d36cf68771bf4f584ba3386e37.tar.gz |
[2.2.x] Fixed #31031 -- Fixed data loss in admin changelist view when formset's prefix contains regex special chars.
Regression in b18650a2634890aa758abae2f33875daa13a9ba3.
Backport of 52936efacec4df05df2d9872c09c3332335bf21b from master
-rw-r--r-- | django/contrib/admin/options.py | 4 | ||||
-rw-r--r-- | docs/releases/2.2.8.txt | 4 | ||||
-rw-r--r-- | tests/admin_changelist/tests.py | 20 |
3 files changed, 26 insertions, 2 deletions
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 52ad319ef2..520e3d023e 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -1638,7 +1638,9 @@ class ModelAdmin(BaseModelAdmin): def _get_edited_object_pks(self, request, prefix): """Return POST data values of list_editable primary keys.""" - pk_pattern = re.compile(r'{}-\d+-{}$'.format(prefix, self.model._meta.pk.name)) + pk_pattern = re.compile( + r'{}-\d+-{}$'.format(re.escape(prefix), self.model._meta.pk.name) + ) return [value for key, value in request.POST.items() if pk_pattern.match(key)] def _get_list_editable_queryset(self, request, prefix): diff --git a/docs/releases/2.2.8.txt b/docs/releases/2.2.8.txt index 0c2b3eabdf..e9bd1ed1cb 100644 --- a/docs/releases/2.2.8.txt +++ b/docs/releases/2.2.8.txt @@ -10,4 +10,6 @@ Django 2.2.8 fixes several bugs in 2.2.7 and adds compatibility with Python Bugfixes ======== -* ... +* Fixed a data loss possibility in the admin changelist view when a custom + :ref:`formset's prefix <formset-prefix>` contains regular expression special + characters, e.g. `'$'` (:ticket:`31031`). diff --git a/tests/admin_changelist/tests.py b/tests/admin_changelist/tests.py index dfd8e91451..464e6904d8 100644 --- a/tests/admin_changelist/tests.py +++ b/tests/admin_changelist/tests.py @@ -827,6 +827,26 @@ class ChangeListTests(TestCase): 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) + 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', + } + superuser = self._create_superuser('superuser') + self.client.force_login(superuser) + 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$') + 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) |