Ticket #15574: inline-formset-test.diff

File inline-formset-test.diff, 6.1 KB (added by Paul Oswald, 13 years ago)
  • AUTHORS

    diff --git a/AUTHORS b/AUTHORS
    index 6c90cd0..41367e7 100644
    a b answer newbie questions, and generally made Django that much better:  
    369369    Neal Norwitz <nnorwitz@google.com>
    370370    Todd O'Bryan <toddobryan@mac.com>
    371371    Selwin Ong <selwin@ui.co.id>
     372    Paul Oswald <pauloswald@gmail.com>
    372373    Christian Oudard <christian.oudard@gmail.com>
    373374    oggie rob <oz.robharvey@gmail.com>
    374375    oggy <ognjen.maric@gmail.com>
  • tests/regressiontests/admin_inlines/models.py

    diff --git a/tests/regressiontests/admin_inlines/models.py b/tests/regressiontests/admin_inlines/models.py
    index bb299f3..a6acc6d 100644
    a b class Holder2(models.Model):  
    6666    dummy = models.IntegerField()
    6767
    6868
     69# Objects for bug #15574 Test
     70class Thing(models.Model):
     71    description = models.CharField(max_length=256)
     72
     73class ThingItem(models.Model):
     74    description = models.CharField(max_length=256)
     75    thing = models.ForeignKey(Thing)
     76
     77class ThingItemInline(admin.TabularInline):
     78    model = ThingItem
     79    extra = 0
     80
     81class ThingAdmin(admin.ModelAdmin):
     82    inlines = [ThingItemInline,]
     83
     84admin.site.register(Thing, ThingAdmin)
     85
     86
    6987class Inner2(models.Model):
    7088    dummy = models.IntegerField()
    7189    holder = models.ForeignKey(Holder2)
  • tests/regressiontests/admin_inlines/tests.py

    diff --git a/tests/regressiontests/admin_inlines/tests.py b/tests/regressiontests/admin_inlines/tests.py
    index 915c6fa..5bc11c3 100644
    a b  
    11from django.contrib.admin.helpers import InlineAdminForm
    22from django.contrib.contenttypes.models import ContentType
    33from django.test import TestCase
     4from django.core.urlresolvers import reverse
    45
    56# local test models
    67from models import (Holder, Inner, InnerInline, Holder2, Inner2, Holder3,
    7     Inner3, Person, OutfitItem, Fashionista, Teacher, Parent, Child)
    8 
     8    Inner3, Person, OutfitItem, Fashionista, Teacher, Parent, Child, Thing, ThingItem)
    99
    1010class TestInline(TestCase):
    1111    fixtures = ['admin-views-users.xml']
    class TestInlineAdminForm(TestCase):  
    136136        iaf = InlineAdminForm(None, None, {}, {}, joe)
    137137        parent_ct = ContentType.objects.get_for_model(Parent)
    138138        self.assertEqual(iaf.original.content_type, parent_ct)
     139
     140class TestEditingInlineViews(TestCase):
     141    fixtures = ['admin-views-users.xml']
     142
     143    def setUp(self):
     144        result = self.client.login(username='super', password='secret')
     145        self.failUnlessEqual(result, True)
     146        # Set up a thing to be modified in the test
     147        self.thing = Thing.objects.create(description="Parent object")
     148        self.thing_item_1 = ThingItem.objects.create(description="Item #1", thing=self.thing)
     149        self.thing_item_2 = ThingItem.objects.create(description="Item #2", thing=self.thing)
     150
     151    def tearDown(self):
     152        self.client.logout()
     153        self.thing_item_1.delete()
     154        self.thing_item_2.delete()
     155        self.thing.delete()
     156
     157    def test_concurrent_editing_views(self):
     158        """
     159        A ``POST`` to the edit view by two clients simultaneously is properly handled
     160
     161        See issue #15574
     162
     163        We are going to simulate two test clients by submitting slightly different data twice.
     164        This would be equivalent to working with two tabs open in a browser. Individually each of
     165        these forms is valid but the second one is invalid when submitted one after the other. The
     166        server needs to handle this case.
     167        """
     168
     169        data = [
     170            # An existing item has been deleted.
     171            {
     172                u'description': [u'A new description'],
     173                u'thingitem_set-MAX_NUM_FORMS': [u'0'],
     174                u'thingitem_set-TOTAL_FORMS': [u'2'],
     175                u'thingitem_set-INITIAL_FORMS': [u'2'],
     176                u'thingitem_set-0-DELETE': [u''],
     177                u'thingitem_set-0-id': [u'%s' % (self.thing_item_1.pk,)],
     178                u'thingitem_set-0-thing': [u'%s' % (self.thing.pk,)],
     179                u'thingitem_set-0-description': [u'New item #1 description'],
     180                u'thingitem_set-1-DELETE': [u'on'],
     181                u'thingitem_set-1-id': [u'%s' % (self.thing_item_2.pk,)],
     182                u'thingitem_set-1-thing': [u'%s' % (self.thing.pk,)],
     183                u'thingitem_set-1-description': [u'Deleted item #2 description'],
     184            },
     185
     186            # In this second form, we are now attempting to edit the deleted item. This form is
     187            # invalid but the user submitting it doesn't know that yet.
     188            {
     189                u'description': [u'A new description #2'],
     190                u'thingitem_set-MAX_NUM_FORMS': [u'0'],
     191                u'thingitem_set-TOTAL_FORMS': [u'2'],
     192                u'thingitem_set-INITIAL_FORMS': [u'2'],
     193                u'thingitem_set-0-DELETE': [u''],
     194                u'thingitem_set-0-id': [u'%s' % (self.thing_item_1.pk,)],
     195                u'thingitem_set-0-thing': [u'%s' % (self.thing.pk,)],
     196                u'thingitem_set-0-description': [u'New item #1 description'],
     197                u'thingitem_set-1-DELETE': [u''],
     198                u'thingitem_set-1-id': [u'%s' % (self.thing_item_2.pk,)],
     199                u'thingitem_set-1-thing': [u'%s' % (self.thing.pk,)],
     200                u'thingitem_set-1-description': [u'Deleted item #2 description'],
     201            },
     202        ]
     203        edit_url = 'admin:%s_%s_change' %(self.thing._meta.app_label,  self.thing._meta.module_name)
     204        view_url = 'admin:%s_%s_changelist' %(self.thing._meta.app_label,  self.thing._meta.module_name)
     205
     206        count = Thing.objects.count()
     207        response = self.client.post(reverse(edit_url, args=[self.thing.pk]), data[0])
     208
     209        # Check our first edit was accepted
     210        self.assertRedirects(response, reverse(view_url), 302, 200)
     211
     212        # Submit the second form. (this might be a second tab in the browser, or a second user)
     213        response = self.client.post(reverse(edit_url, args=[self.thing.pk]), data[1])
     214
     215        # Check our second edit was handled
     216        self.assertRedirects(response, reverse(view_url), 302, 200)
     217
     218
Back to Top