summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKamil Braun <kb346840@students.mimuw.edu.pl>2014-11-27 19:34:14 +0100
committerTim Graham <timograham@gmail.com>2014-12-02 08:43:59 -0500
commitccc30ffe57e5f1e4dbda371b8a1d00c19a3150aa (patch)
tree6e75016a6a99b24135263fadc27d4a804981c7b7
parent3a42d9730cbb07ffbb983791e631f5d0a6746f68 (diff)
[1.7.x] Fixed #23934 -- Fixed regression in admin views obj parameter.
Backport of 0623f4dea46eefba46efde6c6528f7d813ef4391 from master
-rw-r--r--django/contrib/admin/options.py10
-rw-r--r--docs/releases/1.7.2.txt4
-rw-r--r--tests/admin_views/admin.py28
-rw-r--r--tests/admin_views/models.py9
-rw-r--r--tests/admin_views/tests.py48
5 files changed, 92 insertions, 7 deletions
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index 3d0faf0e33..e1f56c6f9b 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -1399,7 +1399,7 @@ class ModelAdmin(BaseModelAdmin):
else:
form_validated = False
new_object = form.instance
- formsets, inline_instances = self._create_formsets(request, new_object)
+ formsets, inline_instances = self._create_formsets(request, new_object, change=not add)
if all_valid(formsets) and form_validated:
self.save_model(request, new_object, form, not add)
self.save_related(request, form, formsets, not add)
@@ -1414,10 +1414,10 @@ class ModelAdmin(BaseModelAdmin):
if add:
initial = self.get_changeform_initial_data(request)
form = ModelForm(initial=initial)
- formsets, inline_instances = self._create_formsets(request, self.model())
+ formsets, inline_instances = self._create_formsets(request, self.model(), change=False)
else:
form = ModelForm(instance=obj)
- formsets, inline_instances = self._create_formsets(request, obj)
+ formsets, inline_instances = self._create_formsets(request, obj, change=True)
adminForm = helpers.AdminForm(
form,
@@ -1702,13 +1702,13 @@ class ModelAdmin(BaseModelAdmin):
"admin/object_history.html"
], context, current_app=self.admin_site.name)
- def _create_formsets(self, request, obj):
+ def _create_formsets(self, request, obj, change):
"Helper function to generate formsets for add/change_view."
formsets = []
inline_instances = []
prefixes = {}
get_formsets_args = [request]
- if obj.pk:
+ if change:
get_formsets_args.append(obj)
for FormSet, inline in self.get_formsets_with_inlines(*get_formsets_args):
prefix = FormSet.get_default_prefix()
diff --git a/docs/releases/1.7.2.txt b/docs/releases/1.7.2.txt
index c01dca9f58..85ebd1a6dc 100644
--- a/docs/releases/1.7.2.txt
+++ b/docs/releases/1.7.2.txt
@@ -94,3 +94,7 @@ Bugfixes
* Fixed a crash when ``RunSQL`` SQL content was collected by the schema editor,
typically when using ``sqlmigrate`` (:ticket:`23909`).
+
+* Fixed a regression in ``contrib.admin`` add/change views which caused some
+ ``ModelAdmin`` methods to receive the incorrect ``obj`` value
+ (:ticket:`23934`).
diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py
index 964ea83599..9a05df614a 100644
--- a/tests/admin_views/admin.py
+++ b/tests/admin_views/admin.py
@@ -18,7 +18,8 @@ from django.contrib.admin import BooleanFieldListFilter
from django.utils.safestring import mark_safe
from django.utils.six import StringIO
-from .models import (Article, Chapter, Child, Parent, Picture, Widget,
+from .models import (
+ Article, Chapter, Child, Parent, Picture, Widget,
DooHickey, Grommet, Whatsit, FancyDoodad, Category, Link,
PrePopulatedPost, PrePopulatedSubPost, CustomArticle, Section,
ModelWithStringPrimaryKey, Color, Thing, Actor, Inquisition, Sketch,
@@ -37,7 +38,9 @@ from .models import (Article, Chapter, Child, Parent, Picture, Widget,
State, City, Restaurant, Worker, ParentWithDependentChildren,
DependentChild, StumpJoke, FieldOverridePost, FunkyTag,
ReferencedByParent, ChildOfReferer, ReferencedByInline,
- InlineReference, InlineReferer, Recipe, Ingredient, NotReferenced)
+ InlineReference, InlineReferer, Recipe, Ingredient, NotReferenced,
+ ExplicitlyProvidedPK, ImplicitlyGeneratedPK,
+)
def callable_year(dt_value):
@@ -835,6 +838,25 @@ class InlineRefererAdmin(admin.ModelAdmin):
inlines = [InlineReferenceInline]
+class GetFormsetsArgumentCheckingAdmin(admin.ModelAdmin):
+ fields = ['name']
+
+ def add_view(self, request, *args, **kwargs):
+ request.is_add_view = True
+ return super(GetFormsetsArgumentCheckingAdmin, self).add_view(request, *args, **kwargs)
+
+ def change_view(self, request, *args, **kwargs):
+ request.is_add_view = False
+ return super(GetFormsetsArgumentCheckingAdmin, self).change_view(request, *args, **kwargs)
+
+ def get_formsets_with_inlines(self, request, obj=None):
+ if request.is_add_view and obj is not None:
+ raise Exception("'obj' passed to get_formsets_with_inlines wasn't None during add_view")
+ if not request.is_add_view and obj is None:
+ raise Exception("'obj' passed to get_formsets_with_inlines was None during change_view")
+ return super(GetFormsetsArgumentCheckingAdmin, self).get_formsets_with_inlines(request, obj)
+
+
site = admin.AdminSite(name="admin")
site.register(Article, ArticleAdmin)
site.register(CustomArticle, CustomArticleAdmin)
@@ -934,6 +956,8 @@ site.register(StumpJoke)
site.register(Recipe)
site.register(Ingredient)
site.register(NotReferenced)
+site.register(ExplicitlyProvidedPK, GetFormsetsArgumentCheckingAdmin)
+site.register(ImplicitlyGeneratedPK, GetFormsetsArgumentCheckingAdmin)
# Register core models we need in our tests
from django.contrib.auth.models import User, Group
diff --git a/tests/admin_views/models.py b/tests/admin_views/models.py
index 9d5b49c89f..341b7aec65 100644
--- a/tests/admin_views/models.py
+++ b/tests/admin_views/models.py
@@ -867,3 +867,12 @@ class Ingredient(models.Model):
class NotReferenced(models.Model):
# Don't point any FK at this model.
pass
+
+
+# Models for #23934
+class ExplicitlyProvidedPK(models.Model):
+ name = models.IntegerField(primary_key=True)
+
+
+class ImplicitlyGeneratedPK(models.Model):
+ name = models.IntegerField(unique=True)
diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py
index 50d68df2a2..b801fedbbb 100644
--- a/tests/admin_views/tests.py
+++ b/tests/admin_views/tests.py
@@ -5056,3 +5056,51 @@ class AdminGenericRelationTests(TestCase):
validator.validate_list_filter(GenericFKAdmin, Plot)
except ImproperlyConfigured:
self.fail("Couldn't validate a GenericRelation -> FK path in ModelAdmin.list_filter")
+
+
+@override_settings(
+ PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',),
+ ROOT_URLCONF="admin_views.urls",
+)
+class GetFormsetsWithInlinesArgumentTest(TestCase):
+ """
+ #23934 - When adding a new model instance in the admin, the 'obj' argument
+ of get_formsets_with_inlines() should be None. When changing, it should be
+ equal to the existing model instance.
+ The GetFormsetsArgumentCheckingAdmin ModelAdmin throws an exception
+ if obj is not None during add_view or obj is None during change_view.
+ """
+ fixtures = ['admin-views-users.xml']
+
+ def setUp(self):
+ self.client.login(username='super', password='secret')
+
+ def test_explicitly_provided_pk(self):
+ post_data = {'name': '1'}
+ try:
+ response = self.client.post('/test_admin/admin/admin_views/explicitlyprovidedpk/add/', post_data)
+ except Exception as e:
+ self.fail(e)
+ self.assertEqual(response.status_code, 302)
+
+ post_data = {'name': '2'}
+ try:
+ response = self.client.post('/test_admin/admin/admin_views/explicitlyprovidedpk/1/', post_data)
+ except Exception as e:
+ self.fail(e)
+ self.assertEqual(response.status_code, 302)
+
+ def test_implicitly_generated_pk(self):
+ post_data = {'name': '1'}
+ try:
+ response = self.client.post('/test_admin/admin/admin_views/implicitlygeneratedpk/add/', post_data)
+ except Exception as e:
+ self.fail(e)
+ self.assertEqual(response.status_code, 302)
+
+ post_data = {'name': '2'}
+ try:
+ response = self.client.post('/test_admin/admin/admin_views/implicitlygeneratedpk/1/', post_data)
+ except Exception as e:
+ self.fail(e)
+ self.assertEqual(response.status_code, 302)