mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	[1.7.x] Fixed #23934 -- Fixed regression in admin views obj parameter.
Backport of 0623f4dea4 from master
			
			
This commit is contained in:
		| @@ -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() | ||||
|   | ||||
| @@ -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`). | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user