Code

Ticket #13223: 13223-2.diff

File 13223-2.diff, 6.8 KB (added by ramiro, 2 years ago)

Patch updated to current trunk status, still needs work

Line 
1diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
2--- a/django/contrib/admin/options.py
3+++ b/django/contrib/admin/options.py
4@@ -1003,6 +1003,7 @@
5             'inline_admin_formsets': inline_admin_formsets,
6             'errors': helpers.AdminErrorList(form, formsets),
7             'app_label': opts.app_label,
8+            'saveasnew': "_saveasnew" in request.POST,
9         }
10         context.update(extra_context or {})
11         return self.render_change_form(request, context, form_url=form_url, add=True)
12diff --git a/django/contrib/admin/templates/admin/change_form.html b/django/contrib/admin/templates/admin/change_form.html
13--- a/django/contrib/admin/templates/admin/change_form.html
14+++ b/django/contrib/admin/templates/admin/change_form.html
15@@ -66,6 +66,7 @@
16 
17 {% block submit_buttons_bottom %}{% submit_row %}{% endblock %}
18 
19+{% if saveasnew %}<input type="hidden" value="_saveasnew" name="_saveasnew">{% endif %}
20 {% if adminform and add %}
21    <script type="text/javascript">document.getElementById("{{ adminform.first_field.id_for_label }}").focus();</script>
22 {% endif %}
23diff --git a/tests/regressiontests/admin_inlines/admin.py b/tests/regressiontests/admin_inlines/admin.py
24--- a/tests/regressiontests/admin_inlines/admin.py
25+++ b/tests/regressiontests/admin_inlines/admin.py
26@@ -113,6 +113,16 @@
27     model = Profile
28     extra = 1
29 
30+
31+class BlockInline(admin.TabularInline):
32+    model = Block
33+
34+
35+class PostAdmin(admin.ModelAdmin):
36+    save_as = True
37+    inlines = [BlockInline]
38+
39+
40 site.register(TitleCollection, inlines=[TitleInline])
41 # Test bug #12561 and #12778
42 # only ModelAdmin media
43@@ -128,4 +138,6 @@
44 site.register(Holder4, Holder4Admin)
45 site.register(Author, AuthorAdmin)
46 site.register(CapoFamiglia, inlines=[ConsigliereInline, SottoCapoInline])
47-site.register(ProfileCollection, inlines=[ProfileInline])
48\ No newline at end of file
49+site.register(ProfileCollection, inlines=[ProfileInline])
50+
51+site.register(Post, PostAdmin)
52diff --git a/tests/regressiontests/admin_inlines/models.py b/tests/regressiontests/admin_inlines/models.py
53--- a/tests/regressiontests/admin_inlines/models.py
54+++ b/tests/regressiontests/admin_inlines/models.py
55@@ -145,4 +145,16 @@
56 class Profile(models.Model):
57     collection = models.ForeignKey(ProfileCollection, blank=True, null=True)
58     first_name = models.CharField(max_length=100)
59-    last_name = models.CharField(max_length=100)
60\ No newline at end of file
61+    last_name = models.CharField(max_length=100)
62+
63+
64+# Models for testing bug #13223 fix
65+class Post(models.Model):
66+    title = models.CharField(max_length=200)
67+
68+class Block(models.Model):
69+    post = models.ForeignKey(Post)
70+    slug = models.CharField(max_length=200, unique=True)
71+
72+    def __unicode__(self):
73+        return self.slug
74diff --git a/tests/regressiontests/admin_inlines/tests.py b/tests/regressiontests/admin_inlines/tests.py
75--- a/tests/regressiontests/admin_inlines/tests.py
76+++ b/tests/regressiontests/admin_inlines/tests.py
77@@ -10,7 +10,7 @@
78 from .admin import InnerInline
79 from .models import (Holder, Inner, Holder2, Inner2, Holder3, Inner3, Person,
80     OutfitItem, Fashionista, Teacher, Parent, Child, Author, Book, Profile,
81-    ProfileCollection)
82+    ProfileCollection, Post, Block)
83 
84 
85 class TestInline(TestCase):
86@@ -145,6 +145,86 @@
87                 '<input id="id_-2-0-name" type="text" class="vTextField" '
88                 'name="-2-0-name" maxlength="100" />')
89 
90+    def test_save_as_new_with_validation_error_in_inlines(self):
91+        """
92+        #13223 - ValueError shouldn't happen after using 'Save as new' and
93+        correcting a validation error in an inline.
94+        """
95+        p = Post.objects.create(title='Post title')
96+        b1 = p.block_set.create(slug='test1')
97+        b2 = p.block_set.create(slug='test2')
98+
99+        initial_posts_count = Post.objects.count()
100+        initial_blocks_count = Block.objects.count()
101+
102+        # Emulate edition of our Post object in the admin and then submittal
103+        # with the 'Save as new' button but triggering a validation error in
104+        # the Block inlines
105+        data = {
106+            'title': 'Second Post title',
107+
108+            'block_set-TOTAL_FORMS': 5,
109+            'block_set-INITIAL_FORMS': 2,
110+            'block_set-MAX_NUM_FORMS': 0,
111+            'block_set-0-id': b1.id,
112+            'block_set-0-post': p.id,
113+            'block_set-0-slug': b1.slug,
114+            'block_set-1-id': b2.id,
115+            'block_set-1-post': p.id,
116+            'block_set-1-slug': b2.slug,
117+            'block_set-2-id': '',
118+            'block_set-2-post': p.id,
119+            'block_set-2-slug': '',
120+            'block_set-3-id': '',
121+            'block_set-3-post': p.id,
122+            'block_set-3-slug': '',
123+            'block_set-4-id': '',
124+            'block_set-4-post': p.id,
125+            'block_set-4-slug': '',
126+            'block_set-__prefix__-id': '',
127+            'block_set-__prefix__-post': p.id,
128+            'block_set-__prefix__-slug': '',
129+
130+            '_saveasnew': u'Save as new',
131+        }
132+        response = self.client.post('/admin/admin_inlines/post/%s/' % p.id, data)
133+        self.assertEqual(response.status_code, 200)
134+        # Verify that an error has been reported
135+        self.assertEqual(response.context['inline_admin_formset'].formset.errors[0]['slug'],
136+            [u'Block with this Slug already exists.'])
137+        self.assertContains(response, '<input type="hidden" value="_saveasnew" name="_saveasnew">')
138+
139+        # Correct the inline data so it validates. Also, add a new Block inline
140+        # (for a total of three). This time we are presented with the 'Save'
141+        # button, use it to submit the form.
142+        data = {
143+            'title': 'Second Post title',
144+
145+            'block_set-TOTAL_FORMS': 5,
146+            'block_set-INITIAL_FORMS': 2,
147+            'block_set-MAX_NUM_FORMS': 0,
148+            'block_set-0-slug': 'test4',
149+            'block_set-1-slug': 'test5',
150+            'block_set-2-slug': 'test6',
151+            'block_set-3-slug': '',
152+            'block_set-4-slug': '',
153+            'block_set-__prefix__-id': '',
154+            'block_set-__prefix__-post': p.id,
155+            'block_set-__prefix__-slug': '',
156+
157+            '_saveasnew': u'_saveasnew',
158+            '_save': u'Save',
159+        }
160+        # Re-submit the form, take in account we will be redirected:
161+        response = self.client.post(
162+            '/admin/admin_inlines/post/%s/' % p.id,
163+            data, follow=True)
164+        self.assertEqual(response.status_code, 200)
165+        # Verify the new objects were correctly created
166+        self.assertEqual(Post.objects.count(), initial_posts_count + 1)
167+        self.assertEqual(Block.objects.count(), initial_blocks_count + 3)
168+
169+
170 class TestInlineMedia(TestCase):
171     urls = "regressiontests.admin_inlines.urls"
172     fixtures = ['admin-views-users.xml']