Ticket #16115: 16115.modeladmin-save-related.2.diff

File 16115.modeladmin-save-related.2.diff, 7.6 KB (added by Julien Phalip, 6 years ago)

Patch updated to latest trunk

  • django/contrib/admin/options.py

    diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
    index e9064bb..72e9f31 100644
    a b class ModelAdmin(BaseModelAdmin): 
    690690        """
    691691        formset.save()
    692692
     693    def save_related(self, request, form, formsets, change):
     694        """
     695        Given the ``HttpRequest``, the parent ``ModelForm`` instance, the list
     696        of inline formsets and a boolean value based on whether the parent is
     697        being added or changed, save the related objects to the database. Note
     698        that at this point save_form() and save_model() have already been
     699        called.
     700        """
     701        form.save_m2m()
     702        for formset in formsets:
     703            self.save_formset(request, form, formset, change=change)
     704
    693705    def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
    694706        opts = self.model._meta
    695707        app_label = opts.app_label
    class ModelAdmin(BaseModelAdmin): 
    893905                                  prefix=prefix, queryset=inline.queryset(request))
    894906                formsets.append(formset)
    895907            if all_valid(formsets) and form_validated:
    896                 self.save_model(request, new_object, form, change=False)
    897                 form.save_m2m()
    898                 for formset in formsets:
    899                     self.save_formset(request, form, formset, change=False)
    900 
     908                self.save_model(request, new_object, form, False)
     909                self.save_related(request, form, formsets, False)
    901910                self.log_addition(request, new_object)
    902911                return self.response_add(request, new_object)
    903912        else:
    class ModelAdmin(BaseModelAdmin): 
    9951004                formsets.append(formset)
    9961005
    9971006            if all_valid(formsets) and form_validated:
    998                 self.save_model(request, new_object, form, change=True)
    999                 form.save_m2m()
    1000                 for formset in formsets:
    1001                     self.save_formset(request, form, formset, change=True)
    1002 
     1007                self.save_model(request, new_object, form, True)
     1008                self.save_related(request, form, formsets, True)
    10031009                change_message = self.construct_change_message(request, form, formsets)
    10041010                self.log_change(request, new_object, change_message)
    10051011                return self.response_change(request, new_object)
  • docs/ref/contrib/admin/index.txt

    diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt
    index e0ddd4a..e5560c2 100644
    a b templates used by the :class:`ModelAdmin` views: 
    949949                    instance.save()
    950950                formset.save_m2m()
    951951
     952.. method:: ModelAdmin.save_related(self, request, form, formsets, change)
     953
     954    .. versionadded:: 1.4
     955
     956    The ``save_related`` method is given the ``HttpRequest``, the parent
     957    ``ModelForm`` instance, the list of inline formsets and a boolean value
     958    based on whether the parent is being added or changed. Here you can do any
     959    pre- or post-save operations for objects related to the parent. Note
     960    that at this point the parent object and its form have already been saved.
     961
    952962.. method:: ModelAdmin.get_readonly_fields(self, request, obj=None)
    953963
    954964    .. versionadded:: 1.2
  • docs/releases/1.4.txt

    diff --git a/docs/releases/1.4.txt b/docs/releases/1.4.txt
    index ddbcda9..affe361 100644
    a b elements of the :attr:`~django.contrib.admin.ModelAdmin.ordering` attribute, and 
    5858sorting on multiple columns by clicking on headers is designed to work similarly
    5959to how desktop GUIs do it.
    6060
     61``ModelAdmin.save_related()``
     62~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     63
     64A new :meth:`~django.contrib.admin.ModelAdmin.save_related` hook was added to
     65:mod:`~django.contrib.admin.ModelAdmin` to ease the customization of how
     66related objects are saved in the admin.
     67
    6168Tools for cryptographic signing
    6269~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    6370
  • tests/regressiontests/admin_views/models.py

    diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py
    index 52d96a9..8d79f44 100644
    a b class ParentAdmin(admin.ModelAdmin): 
    391391    model = Parent
    392392    inlines = [ChildInline]
    393393
     394    def save_related(self, request, form, formsets, change):
     395        super(ParentAdmin, self).save_related(request, form, formsets, change)
     396        first_name, last_name = form.instance.name.split()
     397        for child in form.instance.child_set.all():
     398            if len(child.name.split()) < 2:
     399                child.name = child.name + ' ' + last_name
     400                child.save()
     401
    394402class EmptyModel(models.Model):
    395403    def __unicode__(self):
    396404        return "Primary key = %s" % self.id
  • tests/regressiontests/admin_views/tests.py

    diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py
    index 25056b5..7128f04 100644
    a b from models import (Article, BarAccount, CustomArticle, EmptyModel, 
    3838    Category, Post, Plot, FunkyTag, Chapter, Book, Promo, WorkHour, Employee,
    3939    Question, Answer, Inquisition, Actor, FoodDelivery,
    4040    RowLevelChangePermissionModel, Paper, CoverLetter, Story, OtherStory,
    41     ComplexSortedPerson)
     41    ComplexSortedPerson, Parent, Child)
    4242
    4343
    4444class AdminViewBasicTest(TestCase):
    class DateHierarchyTests(TestCase): 
    31133113            self.assert_non_localized_year(response, 2000)
    31143114            self.assert_non_localized_year(response, 2003)
    31153115            self.assert_non_localized_year(response, 2005)
     3116
     3117class AdminCustomSaveRelatedTests(TestCase):
     3118    """
     3119    Ensure that one can easily customize the way related objects are saved.
     3120    Refs #16115.
     3121    """
     3122    fixtures = ['admin-views-users.xml']
     3123
     3124    def setUp(self):
     3125        self.client.login(username='super', password='secret')
     3126
     3127    def test_should_be_able_to_edit_related_objects_on_add_view(self):
     3128        post = {
     3129            'child_set-TOTAL_FORMS': '3',
     3130            'child_set-INITIAL_FORMS': '0',
     3131            'name': 'Josh Stone',
     3132            'child_set-0-name': 'Paul',
     3133            'child_set-1-name': 'Catherine',
     3134        }
     3135        response = self.client.post('/test_admin/admin/admin_views/parent/add/', post)
     3136        self.assertEqual(1, Parent.objects.count())
     3137        self.assertEqual(2, Child.objects.count())
     3138
     3139        children_names = list(Child.objects.order_by('name').values_list('name', flat=True))
     3140
     3141        self.assertEqual('Josh Stone', Parent.objects.latest('id').name)
     3142        self.assertEqual([u'Catherine Stone', u'Paul Stone'], children_names)
     3143
     3144    def test_should_be_able_to_edit_related_objects_on_change_view(self):
     3145        parent = Parent.objects.create(name='Josh Stone')
     3146        paul = Child.objects.create(parent=parent, name='Paul')
     3147        catherine = Child.objects.create(parent=parent, name='Catherine')
     3148        post = {
     3149            'child_set-TOTAL_FORMS': '5',
     3150            'child_set-INITIAL_FORMS': '2',
     3151            'name': 'Josh Stone',
     3152            'child_set-0-name': 'Paul',
     3153            'child_set-0-id': paul.id,
     3154            'child_set-1-name': 'Catherine',
     3155            'child_set-1-id': catherine.id,
     3156        }
     3157        response = self.client.post('/test_admin/admin/admin_views/parent/%s/' % parent.id, post)
     3158
     3159        children_names = list(Child.objects.order_by('name').values_list('name', flat=True))
     3160
     3161        self.assertEqual('Josh Stone', Parent.objects.latest('id').name)
     3162        self.assertEqual([u'Catherine Stone', u'Paul Stone'], children_names)
Back to Top