Commit 6acaa523 authored by Greg Chapple's avatar Greg Chapple Committed by Tim Graham
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.
parent 6b63742c
Loading
Loading
Loading
Loading
+17 −10
Original line number Diff line number Diff line
@@ -1308,6 +1308,22 @@ class ModelAdmin(BaseModelAdmin):
            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 @@ class ModelAdmin(BaseModelAdmin):
                    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:
+15 −0
Original line number Diff line number Diff line
@@ -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
~~~~~~~~~~~~~

+4 −0
Original line number Diff line number Diff line
@@ -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`
^^^^^^^^^^^^^^^^^^^^^^^^^^

+4 −0
Original line number Diff line number Diff line
@@ -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)
+13 −0
Original line number Diff line number Diff line
@@ -765,6 +765,19 @@ class AdminViewFormUrlTest(TestCase):
        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):