Fixed #23934 -- Fixed regression in admin views obj parameter.
This commit is contained in:
parent
1da1fe8e16
commit
0623f4dea4
|
@ -1425,7 +1425,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
else:
|
else:
|
||||||
form_validated = False
|
form_validated = False
|
||||||
new_object = form.instance
|
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:
|
if all_valid(formsets) and form_validated:
|
||||||
self.save_model(request, new_object, form, not add)
|
self.save_model(request, new_object, form, not add)
|
||||||
self.save_related(request, form, formsets, not add)
|
self.save_related(request, form, formsets, not add)
|
||||||
|
@ -1440,10 +1440,10 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
if add:
|
if add:
|
||||||
initial = self.get_changeform_initial_data(request)
|
initial = self.get_changeform_initial_data(request)
|
||||||
form = ModelForm(initial=initial)
|
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:
|
else:
|
||||||
form = ModelForm(instance=obj)
|
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(
|
adminForm = helpers.AdminForm(
|
||||||
form,
|
form,
|
||||||
|
@ -1729,13 +1729,13 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
"admin/object_history.html"
|
"admin/object_history.html"
|
||||||
], context, current_app=self.admin_site.name)
|
], 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."
|
"Helper function to generate formsets for add/change_view."
|
||||||
formsets = []
|
formsets = []
|
||||||
inline_instances = []
|
inline_instances = []
|
||||||
prefixes = {}
|
prefixes = {}
|
||||||
get_formsets_args = [request]
|
get_formsets_args = [request]
|
||||||
if obj.pk:
|
if change:
|
||||||
get_formsets_args.append(obj)
|
get_formsets_args.append(obj)
|
||||||
for FormSet, inline in self.get_formsets_with_inlines(*get_formsets_args):
|
for FormSet, inline in self.get_formsets_with_inlines(*get_formsets_args):
|
||||||
prefix = FormSet.get_default_prefix()
|
prefix = FormSet.get_default_prefix()
|
||||||
|
|
|
@ -94,3 +94,7 @@ Bugfixes
|
||||||
|
|
||||||
* Fixed a crash when ``RunSQL`` SQL content was collected by the schema editor,
|
* Fixed a crash when ``RunSQL`` SQL content was collected by the schema editor,
|
||||||
typically when using ``sqlmigrate`` (:ticket:`23909`).
|
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`).
|
||||||
|
|
|
@ -18,7 +18,8 @@ from django.contrib.admin import BooleanFieldListFilter
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.six import StringIO
|
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,
|
DooHickey, Grommet, Whatsit, FancyDoodad, Category, Link,
|
||||||
PrePopulatedPost, PrePopulatedSubPost, CustomArticle, Section,
|
PrePopulatedPost, PrePopulatedSubPost, CustomArticle, Section,
|
||||||
ModelWithStringPrimaryKey, Color, Thing, Actor, Inquisition, Sketch,
|
ModelWithStringPrimaryKey, Color, Thing, Actor, Inquisition, Sketch,
|
||||||
|
@ -37,7 +38,9 @@ from .models import (Article, Chapter, Child, Parent, Picture, Widget,
|
||||||
State, City, Restaurant, Worker, ParentWithDependentChildren,
|
State, City, Restaurant, Worker, ParentWithDependentChildren,
|
||||||
DependentChild, StumpJoke, FieldOverridePost, FunkyTag,
|
DependentChild, StumpJoke, FieldOverridePost, FunkyTag,
|
||||||
ReferencedByParent, ChildOfReferer, ReferencedByInline,
|
ReferencedByParent, ChildOfReferer, ReferencedByInline,
|
||||||
InlineReference, InlineReferer, Recipe, Ingredient, NotReferenced)
|
InlineReference, InlineReferer, Recipe, Ingredient, NotReferenced,
|
||||||
|
ExplicitlyProvidedPK, ImplicitlyGeneratedPK,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def callable_year(dt_value):
|
def callable_year(dt_value):
|
||||||
|
@ -842,6 +845,25 @@ class InlineRefererAdmin(admin.ModelAdmin):
|
||||||
inlines = [InlineReferenceInline]
|
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 = admin.AdminSite(name="admin")
|
||||||
site.site_url = '/my-site-url/'
|
site.site_url = '/my-site-url/'
|
||||||
site.register(Article, ArticleAdmin)
|
site.register(Article, ArticleAdmin)
|
||||||
|
@ -942,6 +964,8 @@ site.register(StumpJoke)
|
||||||
site.register(Recipe)
|
site.register(Recipe)
|
||||||
site.register(Ingredient)
|
site.register(Ingredient)
|
||||||
site.register(NotReferenced)
|
site.register(NotReferenced)
|
||||||
|
site.register(ExplicitlyProvidedPK, GetFormsetsArgumentCheckingAdmin)
|
||||||
|
site.register(ImplicitlyGeneratedPK, GetFormsetsArgumentCheckingAdmin)
|
||||||
|
|
||||||
# Register core models we need in our tests
|
# Register core models we need in our tests
|
||||||
from django.contrib.auth.models import User, Group
|
from django.contrib.auth.models import User, Group
|
||||||
|
|
|
@ -874,3 +874,12 @@ class RecipeIngredient(models.Model):
|
||||||
class NotReferenced(models.Model):
|
class NotReferenced(models.Model):
|
||||||
# Don't point any FK at this model.
|
# Don't point any FK at this model.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# Models for #23934
|
||||||
|
class ExplicitlyProvidedPK(models.Model):
|
||||||
|
name = models.IntegerField(primary_key=True)
|
||||||
|
|
||||||
|
|
||||||
|
class ImplicitlyGeneratedPK(models.Model):
|
||||||
|
name = models.IntegerField(unique=True)
|
||||||
|
|
|
@ -5207,3 +5207,51 @@ class TestEtagWithAdminView(TestCase):
|
||||||
response = self.client.get('/test_admin/admin/')
|
response = self.client.get('/test_admin/admin/')
|
||||||
self.assertEqual(response.status_code, 302)
|
self.assertEqual(response.status_code, 302)
|
||||||
self.assertTrue(response.has_header('ETag'))
|
self.assertTrue(response.has_header('ETag'))
|
||||||
|
|
||||||
|
|
||||||
|
@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)
|
||||||
|
|
Loading…
Reference in New Issue