summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBaptiste Mispelon <bmispelon@gmail.com>2019-11-24 23:09:07 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2019-11-26 09:19:39 +0100
commit7873d3757d3075d36cf68771bf4f584ba3386e37 (patch)
treef06484ef36bf51ee9ac275f37cc3661945389d97
parent2af606003a97559cd2c91b2ca0e41b326752303b (diff)
downloaddjango-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.py4
-rw-r--r--docs/releases/2.2.8.txt4
-rw-r--r--tests/admin_changelist/tests.py20
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)