Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fixed #22135 -- Added ModelAdmin.get_changeform_initial_data().

Allows custom behavior for setting initial form data in ModelAdmin.
By default, initial data is set via GET params. The new method allows
this behavior to be overridden.

Thanks egasimus for the suggestion.
  • Loading branch information...
commit 6acaa5238668593d6d854b28dbfa65e95796585c 1 parent 6b63742
@gchp gchp authored timgraham committed
View
27 django/contrib/admin/options.py
@@ -1308,6 +1308,22 @@ def get_inline_formsets(self, request, formsets, inline_instances,
inline_admin_formsets.append(inline_admin_formset)
return inline_admin_formsets
+ def get_changeform_initial_data(self, request):
+ """
+ Get the initial form data.
+ Unless overridden, this populates from the GET params.
+ """
+ initial = dict(request.GET.items())
+ for k in initial:
+ try:
+ f = self.model._meta.get_field(k)
+ except models.FieldDoesNotExist:
+ continue
+ # We have to special-case M2Ms as a list of comma-separated PKs.
+ if isinstance(f, models.ManyToManyField):
+ initial[k] = initial[k].split(",")
+ return initial
+
@csrf_protect_m
@transaction.atomic
def changeform_view(self, request, object_id=None, form_url='', extra_context=None):
@@ -1358,16 +1374,7 @@ def changeform_view(self, request, object_id=None, form_url='', extra_context=No
return self.response_change(request, new_object)
else:
if add:
- # Prepare the dict of initial data from the request.
- # We have to special-case M2Ms as a list of comma-separated PKs.
- initial = dict(request.GET.items())
- for k in initial:
- try:
- f = opts.get_field(k)
- except models.FieldDoesNotExist:
- continue
- if isinstance(f, models.ManyToManyField):
- initial[k] = initial[k].split(",")
+ initial = self.get_changeform_initial_data(request)
form = ModelForm(initial=initial)
formsets, inline_instances = self._create_formsets(request, self.model())
else:
View
15 docs/ref/contrib/admin/index.txt
@@ -1709,6 +1709,21 @@ templates used by the :class:`ModelAdmin` views:
``obj_display`` is a string with the name of the deleted
object.
+.. method:: ModelAdmin.get_changeform_initial_data(request)
+
+ .. versionadded:: 1.7
+
+ A hook for the initial data on admin change forms. By default, fields are
+ given initial values from ``GET`` parameters. For instance,
+ ``?name=initial_value`` will set the ``name`` field's initial value to be
+ ``initial_value``.
+
+ This method should return a dictionary in the form
+ ``{'fieldname': 'fieldval'}``::
+
+ def get_changeform_initial_data(self, request):
+ return {'name': 'custom_initial_value'}
+
Other methods
~~~~~~~~~~~~~
View
4 docs/releases/1.7.txt
@@ -308,6 +308,10 @@ Minor features
<django.contrib.admin.ModelAdmin.list_display>` value by prefixing the
``admin_order_field`` value with a hyphen.
+* The :meth:`ModelAdmin.get_changeform_initial_data()
+ <django.contrib.admin.ModelAdmin.get_changeform_initial_data>` method may be
+ overridden to define custom behavior for setting initial change form data.
+
:mod:`django.contrib.auth`
^^^^^^^^^^^^^^^^^^^^^^^^^^
View
4 tests/admin_views/admin.py
@@ -796,6 +796,10 @@ class RestaurantAdmin(admin.ModelAdmin):
inlines = [WorkerInlineAdmin]
view_on_site = False
+ def get_changeform_initial_data(self, request):
+ return {'name': 'overridden_value'}
+
+
site = admin.AdminSite(name="admin")
site.register(Article, ArticleAdmin)
site.register(CustomArticle, CustomArticleAdmin)
View
13 tests/admin_views/tests.py
@@ -765,6 +765,19 @@ def testChangeFormUrlHasCorrectValue(self):
self.assertTrue('form_url' in response.context, msg='form_url not present in response.context')
self.assertEqual(response.context['form_url'], 'pony')
+ def testInitialDataCanBeOverridden(self):
+ """
+ Tests that the behavior for setting initial
+ form data can be overridden in the ModelAdmin class.
+
+ Usually, the initial value is set via the GET params.
+ """
+ response = self.client.get('/test_admin/%s/admin_views/restaurant/add/' % self.urlbit, {'name': 'test_value'})
+ # this would be the usual behaviour
+ self.assertNotContains(response, 'value="test_value"')
+ # this is the overridden behaviour
+ self.assertContains(response, 'value="overridden_value"')
+
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
class AdminJavaScriptTest(TestCase):
Please sign in to comment.
Something went wrong with that request. Please try again.