summaryrefslogtreecommitdiff
path: root/django/contrib/admin/options.py
diff options
context:
space:
mode:
Diffstat (limited to 'django/contrib/admin/options.py')
-rw-r--r--django/contrib/admin/options.py25
1 files changed, 24 insertions, 1 deletions
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index 1eee19fea4..8d8f263db1 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -1,6 +1,7 @@
import copy
import json
import operator
+import re
from collections import OrderedDict
from functools import partial, reduce, update_wrapper
from urllib.parse import quote as urlquote
@@ -1555,6 +1556,27 @@ class ModelAdmin(BaseModelAdmin):
def change_view(self, request, object_id, form_url='', extra_context=None):
return self.changeform_view(request, object_id, form_url, extra_context)
+ def _get_edited_object_pks(self, request, prefix):
+ """Return POST data values of list_editable primary keys."""
+ pk_pattern = re.compile('{}-\d+-{}$'.format(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):
+ """
+ Based on POST data, return a queryset of the objects that were edited
+ via list_editable.
+ """
+ object_pks = self._get_edited_object_pks(request, prefix)
+ queryset = self.get_queryset(request)
+ validate = queryset.model._meta.pk.to_python
+ try:
+ for pk in object_pks:
+ validate(pk)
+ except ValidationError:
+ # Disable the optimization if the POST data was tampered with.
+ return queryset
+ return queryset.filter(pk__in=object_pks)
+
@csrf_protect_m
def changelist_view(self, request, extra_context=None):
"""
@@ -1629,7 +1651,8 @@ class ModelAdmin(BaseModelAdmin):
# Handle POSTed bulk-edit data.
if request.method == 'POST' and cl.list_editable and '_save' in request.POST:
FormSet = self.get_changelist_formset(request)
- formset = cl.formset = FormSet(request.POST, request.FILES, queryset=self.get_queryset(request))
+ modified_objects = self._get_list_editable_queryset(request, FormSet.get_default_prefix())
+ formset = cl.formset = FormSet(request.POST, request.FILES, queryset=modified_objects)
if formset.is_valid():
changecount = 0
for form in formset.forms: