Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

[1.0.X] Fixed #11042 -- Corrected admin inlines for inherited models.…

… Thanks to jsmullyan for the report, and mir for helpful triage work. Patch includes regression test for #8093, and a commented out test for #10992.

Merge of r10725 from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.0.X@10726 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 0d930ee0e647cdc46517971a8b84a304adb1178e 1 parent cde397d
Russell Keith-Magee authored
8  django/contrib/admin/helpers.py
@@ -138,7 +138,13 @@ def __iter__(self):
138 138
             yield InlineFieldset(self.formset, self.form, name, **options)
139 139
 
140 140
     def has_auto_field(self):
141  
-        return self.form._meta.model._meta.has_auto_field
  141
+        if self.form._meta.model._meta.has_auto_field:
  142
+            return True
  143
+        # Also search any parents for an auto field.
  144
+        for parent in self.form._meta.model._meta.get_parent_list():
  145
+            if parent._meta.has_auto_field:
  146
+                return True
  147
+        return False
142 148
 
143 149
     def field_count(self):
144 150
         # tabular.html uses this function for colspan value.
47  tests/regressiontests/admin_views/models.py
@@ -255,6 +255,52 @@ class Recommendation(Title):
255 255
 class RecommendationAdmin(admin.ModelAdmin):
256 256
     search_fields = ('titletranslation__text', 'recommender__titletranslation__text',)
257 257
 
  258
+class Collector(models.Model):
  259
+    name = models.CharField(max_length=100)
  260
+
  261
+class Widget(models.Model):
  262
+    owner = models.ForeignKey(Collector)
  263
+    name = models.CharField(max_length=100)
  264
+
  265
+class DooHickey(models.Model):
  266
+    code = models.CharField(max_length=10, primary_key=True)
  267
+    owner = models.ForeignKey(Collector)
  268
+    name = models.CharField(max_length=100)
  269
+
  270
+class Grommet(models.Model):
  271
+    code = models.AutoField(primary_key=True)
  272
+    owner = models.ForeignKey(Collector)
  273
+    name = models.CharField(max_length=100)
  274
+
  275
+class Whatsit(models.Model):
  276
+    index = models.IntegerField(primary_key=True)
  277
+    owner = models.ForeignKey(Collector)
  278
+    name = models.CharField(max_length=100)
  279
+
  280
+class Doodad(models.Model):
  281
+    name = models.CharField(max_length=100)
  282
+
  283
+class FancyDoodad(Doodad):
  284
+    owner = models.ForeignKey(Collector)
  285
+    expensive = models.BooleanField(default=True)
  286
+
  287
+class WidgetInline(admin.StackedInline):
  288
+    model = Widget
  289
+
  290
+class DooHickeyInline(admin.StackedInline):
  291
+    model = DooHickey
  292
+
  293
+class GrommetInline(admin.StackedInline):
  294
+    model = Grommet
  295
+
  296
+class WhatsitInline(admin.StackedInline):
  297
+    model = Whatsit
  298
+
  299
+class FancyDoodadInline(admin.StackedInline):
  300
+    model = FancyDoodad
  301
+
  302
+class CollectorAdmin(admin.ModelAdmin):
  303
+    inlines = [WidgetInline, DooHickeyInline, GrommetInline, WhatsitInline, FancyDoodadInline]
258 304
 
259 305
 admin.site.register(Article, ArticleAdmin)
260 306
 admin.site.register(CustomArticle, CustomArticleAdmin)
@@ -270,6 +316,7 @@ class RecommendationAdmin(admin.ModelAdmin):
270 316
 admin.site.register(Picture, PictureAdmin)
271 317
 admin.site.register(Recommendation, RecommendationAdmin)
272 318
 admin.site.register(Recommender)
  319
+admin.site.register(Collector, CollectorAdmin)
273 320
 
274 321
 # We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
275 322
 # That way we cover all four cases:
238  tests/regressiontests/admin_views/tests.py
@@ -14,7 +14,8 @@
14 14
 # local test models
15 15
 from models import (Article, BarAccount, CustomArticle, EmptyModel,
16 16
                     FooAccount, Gallery, ModelWithStringPrimaryKey,
17  
-                    Persona, Picture, Section)
  17
+                    Persona, Picture, Section,
  18
+                    Collector, Widget, Grommet, DooHickey, FancyDoodad, Whatsit)
18 19
 
19 20
 try:
20 21
     set
@@ -994,3 +995,238 @@ def test_inline_file_upload_edit_validation_error_post(self):
994 995
         response = self.client.post('/test_admin/%s/admin_views/gallery/1/' % self.urlbit, post_data)
995 996
         self.failUnless(response._container[0].find("Currently:") > -1)
996 997
 
  998
+
  999
+class AdminInlineTests(TestCase):
  1000
+    fixtures = ['admin-views-users.xml']
  1001
+
  1002
+    def setUp(self):
  1003
+        self.post_data = {
  1004
+            "name": u"Test Name",
  1005
+
  1006
+            "widget_set-TOTAL_FORMS": "3",
  1007
+            "widget_set-INITIAL_FORMS": u"0",
  1008
+            "widget_set-0-id": "",
  1009
+            "widget_set-0-owner": "1",
  1010
+            "widget_set-0-name": "",
  1011
+            "widget_set-1-id": "",
  1012
+            "widget_set-1-owner": "1",
  1013
+            "widget_set-1-name": "",
  1014
+            "widget_set-2-id": "",
  1015
+            "widget_set-2-owner": "1",
  1016
+            "widget_set-2-name": "",
  1017
+
  1018
+            "doohickey_set-TOTAL_FORMS": "3",
  1019
+            "doohickey_set-INITIAL_FORMS": u"0",
  1020
+            "doohickey_set-0-owner": "1",
  1021
+            "doohickey_set-0-code": "",
  1022
+            "doohickey_set-0-name": "",
  1023
+            "doohickey_set-1-owner": "1",
  1024
+            "doohickey_set-1-code": "",
  1025
+            "doohickey_set-1-name": "",
  1026
+            "doohickey_set-2-owner": "1",
  1027
+            "doohickey_set-2-code": "",
  1028
+            "doohickey_set-2-name": "",
  1029
+
  1030
+            "grommet_set-TOTAL_FORMS": "3",
  1031
+            "grommet_set-INITIAL_FORMS": u"0",
  1032
+            "grommet_set-0-code": "",
  1033
+            "grommet_set-0-owner": "1",
  1034
+            "grommet_set-0-name": "",
  1035
+            "grommet_set-1-code": "",
  1036
+            "grommet_set-1-owner": "1",
  1037
+            "grommet_set-1-name": "",
  1038
+            "grommet_set-2-code": "",
  1039
+            "grommet_set-2-owner": "1",
  1040
+            "grommet_set-2-name": "",
  1041
+
  1042
+            "whatsit_set-TOTAL_FORMS": "3",
  1043
+            "whatsit_set-INITIAL_FORMS": u"0",
  1044
+            "whatsit_set-0-owner": "1",
  1045
+            "whatsit_set-0-index": "",
  1046
+            "whatsit_set-0-name": "",
  1047
+            "whatsit_set-1-owner": "1",
  1048
+            "whatsit_set-1-index": "",
  1049
+            "whatsit_set-1-name": "",
  1050
+            "whatsit_set-2-owner": "1",
  1051
+            "whatsit_set-2-index": "",
  1052
+            "whatsit_set-2-name": "",
  1053
+
  1054
+            "fancydoodad_set-TOTAL_FORMS": "3",
  1055
+            "fancydoodad_set-INITIAL_FORMS": u"0",
  1056
+            "fancydoodad_set-0-doodad_ptr": "",
  1057
+            "fancydoodad_set-0-owner": "1",
  1058
+            "fancydoodad_set-0-name": "",
  1059
+            "fancydoodad_set-0-expensive": "on",
  1060
+            "fancydoodad_set-1-doodad_ptr": "",
  1061
+            "fancydoodad_set-1-owner": "1",
  1062
+            "fancydoodad_set-1-name": "",
  1063
+            "fancydoodad_set-1-expensive": "on",
  1064
+            "fancydoodad_set-2-doodad_ptr": "",
  1065
+            "fancydoodad_set-2-owner": "1",
  1066
+            "fancydoodad_set-2-name": "",
  1067
+            "fancydoodad_set-2-expensive": "on",
  1068
+        }
  1069
+
  1070
+        result = self.client.login(username='super', password='secret')
  1071
+        self.failUnlessEqual(result, True)
  1072
+        Collector(pk=1,name='John Fowles').save()
  1073
+
  1074
+    def tearDown(self):
  1075
+        self.client.logout()
  1076
+
  1077
+    def test_simple_inline(self):
  1078
+        "A simple model can be saved as inlines"
  1079
+        # First add a new inline
  1080
+        self.post_data['widget_set-0-name'] = "Widget 1"
  1081
+        response = self.client.post('/test_admin/admin/admin_views/collector/1/', self.post_data)
  1082
+        self.failUnlessEqual(response.status_code, 302)
  1083
+        self.failUnlessEqual(Widget.objects.count(), 1)
  1084
+        self.failUnlessEqual(Widget.objects.all()[0].name, "Widget 1")
  1085
+
  1086
+        # Check that the PK link exists on the rendered form
  1087
+        response = self.client.get('/test_admin/admin/admin_views/collector/1/')
  1088
+        self.assertContains(response, 'name="widget_set-0-id"')
  1089
+
  1090
+        # Now resave that inline
  1091
+        self.post_data['widget_set-INITIAL_FORMS'] = "1"
  1092
+        self.post_data['widget_set-0-id'] = "1"
  1093
+        self.post_data['widget_set-0-name'] = "Widget 1"
  1094
+        response = self.client.post('/test_admin/admin/admin_views/collector/1/', self.post_data)
  1095
+        self.failUnlessEqual(response.status_code, 302)
  1096
+        self.failUnlessEqual(Widget.objects.count(), 1)
  1097
+        self.failUnlessEqual(Widget.objects.all()[0].name, "Widget 1")
  1098
+
  1099
+        # Now modify that inline
  1100
+        self.post_data['widget_set-INITIAL_FORMS'] = "1"
  1101
+        self.post_data['widget_set-0-id'] = "1"
  1102
+        self.post_data['widget_set-0-name'] = "Widget 1 Updated"
  1103
+        response = self.client.post('/test_admin/admin/admin_views/collector/1/', self.post_data)
  1104
+        self.failUnlessEqual(response.status_code, 302)
  1105
+        self.failUnlessEqual(Widget.objects.count(), 1)
  1106
+        self.failUnlessEqual(Widget.objects.all()[0].name, "Widget 1 Updated")
  1107
+
  1108
+    def test_explicit_autofield_inline(self):
  1109
+        "A model with an explicit autofield primary key can be saved as inlines. Regression for #8093"
  1110
+        # First add a new inline
  1111
+        self.post_data['grommet_set-0-name'] = "Grommet 1"
  1112
+        response = self.client.post('/test_admin/admin/admin_views/collector/1/', self.post_data)
  1113
+        self.failUnlessEqual(response.status_code, 302)
  1114
+        self.failUnlessEqual(Grommet.objects.count(), 1)
  1115
+        self.failUnlessEqual(Grommet.objects.all()[0].name, "Grommet 1")
  1116
+
  1117
+        # Check that the PK link exists on the rendered form
  1118
+        response = self.client.get('/test_admin/admin/admin_views/collector/1/')
  1119
+        self.assertContains(response, 'name="grommet_set-0-code"')
  1120
+
  1121
+        # Now resave that inline
  1122
+        self.post_data['grommet_set-INITIAL_FORMS'] = "1"
  1123
+        self.post_data['grommet_set-0-code'] = "1"
  1124
+        self.post_data['grommet_set-0-name'] = "Grommet 1"
  1125
+        response = self.client.post('/test_admin/admin/admin_views/collector/1/', self.post_data)
  1126
+        self.failUnlessEqual(response.status_code, 302)
  1127
+        self.failUnlessEqual(Grommet.objects.count(), 1)
  1128
+        self.failUnlessEqual(Grommet.objects.all()[0].name, "Grommet 1")
  1129
+
  1130
+        # Now modify that inline
  1131
+        self.post_data['grommet_set-INITIAL_FORMS'] = "1"
  1132
+        self.post_data['grommet_set-0-code'] = "1"
  1133
+        self.post_data['grommet_set-0-name'] = "Grommet 1 Updated"
  1134
+        response = self.client.post('/test_admin/admin/admin_views/collector/1/', self.post_data)
  1135
+        self.failUnlessEqual(response.status_code, 302)
  1136
+        self.failUnlessEqual(Grommet.objects.count(), 1)
  1137
+        self.failUnlessEqual(Grommet.objects.all()[0].name, "Grommet 1 Updated")
  1138
+
  1139
+    # def test_char_pk_inline(self):
  1140
+    #     "A model with a character PK can be saved as inlines. Regression for #10992"
  1141
+    #     # First add a new inline
  1142
+    #     self.post_data['doohickey_set-0-code'] = "DH1"
  1143
+    #     self.post_data['doohickey_set-0-name'] = "Doohickey 1"
  1144
+    #     response = self.client.post('/test_admin/admin/admin_views/collector/1/', self.post_data)
  1145
+    #     self.failUnlessEqual(response.status_code, 302)
  1146
+    #     self.failUnlessEqual(DooHickey.objects.count(), 1)
  1147
+    #     self.failUnlessEqual(DooHickey.objects.all()[0].name, "Doohickey 1")
  1148
+    #
  1149
+    #     # Check that the PK link exists on the rendered form
  1150
+    #     response = self.client.get('/test_admin/admin/admin_views/collector/1/')
  1151
+    #     self.assertContains(response, 'name="doohickey_set-0-code"')
  1152
+    #
  1153
+    #     # Now resave that inline
  1154
+    #     self.post_data['doohickey_set-INITIAL_FORMS'] = "1"
  1155
+    #     self.post_data['doohickey_set-0-code'] = "DH1"
  1156
+    #     self.post_data['doohickey_set-0-name'] = "Doohickey 1"
  1157
+    #     response = self.client.post('/test_admin/admin/admin_views/collector/1/', self.post_data)
  1158
+    #     self.failUnlessEqual(response.status_code, 302)
  1159
+    #     self.failUnlessEqual(DooHickey.objects.count(), 1)
  1160
+    #     self.failUnlessEqual(DooHickey.objects.all()[0].name, "Doohickey 1")
  1161
+    #
  1162
+    #     # Now modify that inline
  1163
+    #     self.post_data['doohickey_set-INITIAL_FORMS'] = "1"
  1164
+    #     self.post_data['doohickey_set-0-code'] = "DH1"
  1165
+    #     self.post_data['doohickey_set-0-name'] = "Doohickey 1 Updated"
  1166
+    #     response = self.client.post('/test_admin/admin/admin_views/collector/1/', self.post_data)
  1167
+    #     self.failUnlessEqual(response.status_code, 302)
  1168
+    #     self.failUnlessEqual(DooHickey.objects.count(), 1)
  1169
+    #     self.failUnlessEqual(DooHickey.objects.all()[0].name, "Doohickey 1 Updated")
  1170
+
  1171
+    # def test_integer_pk_inline(self):
  1172
+    #     "A model with an integer PK can be saved as inlines. Regression for #10992"
  1173
+    #     # First add a new inline
  1174
+    #     self.post_data['whatsit_set-0-index'] = "42"
  1175
+    #     self.post_data['whatsit_set-0-name'] = "Whatsit 1"
  1176
+    #     response = self.client.post('/test_admin/admin/admin_views/collector/1/', self.post_data)
  1177
+    #     self.failUnlessEqual(response.status_code, 302)
  1178
+    #     self.failUnlessEqual(Whatsit.objects.count(), 1)
  1179
+    #     self.failUnlessEqual(Whatsit.objects.all()[0].name, "Whatsit 1")
  1180
+    #
  1181
+    #     # Check that the PK link exists on the rendered form
  1182
+    #     response = self.client.get('/test_admin/admin/admin_views/collector/1/')
  1183
+    #     self.assertContains(response, 'name="whatsit_set-0-index"')
  1184
+    #
  1185
+    #     # Now resave that inline
  1186
+    #     self.post_data['whatsit_set-INITIAL_FORMS'] = "1"
  1187
+    #     self.post_data['whatsit_set-0-index'] = "42"
  1188
+    #     self.post_data['whatsit_set-0-name'] = "Whatsit 1"
  1189
+    #     response = self.client.post('/test_admin/admin/admin_views/collector/1/', self.post_data)
  1190
+    #     self.failUnlessEqual(response.status_code, 302)
  1191
+    #     self.failUnlessEqual(Whatsit.objects.count(), 1)
  1192
+    #     self.failUnlessEqual(Whatsit.objects.all()[0].name, "Whatsit 1")
  1193
+    #
  1194
+    #     # Now modify that inline
  1195
+    #     self.post_data['whatsit_set-INITIAL_FORMS'] = "1"
  1196
+    #     self.post_data['whatsit_set-0-index'] = "42"
  1197
+    #     self.post_data['whatsit_set-0-name'] = "Whatsit 1 Updated"
  1198
+    #     response = self.client.post('/test_admin/admin/admin_views/collector/1/', self.post_data)
  1199
+    #     self.failUnlessEqual(response.status_code, 302)
  1200
+    #     self.failUnlessEqual(Whatsit.objects.count(), 1)
  1201
+    #     self.failUnlessEqual(Whatsit.objects.all()[0].name, "Whatsit 1 Updated")
  1202
+
  1203
+    def test_inherited_inline(self):
  1204
+        "An inherited model can be saved as inlines. Regression for #11042"
  1205
+        # First add a new inline
  1206
+        self.post_data['fancydoodad_set-0-name'] = "Fancy Doodad 1"
  1207
+        response = self.client.post('/test_admin/admin/admin_views/collector/1/', self.post_data)
  1208
+        self.failUnlessEqual(response.status_code, 302)
  1209
+        self.failUnlessEqual(FancyDoodad.objects.count(), 1)
  1210
+        self.failUnlessEqual(FancyDoodad.objects.all()[0].name, "Fancy Doodad 1")
  1211
+
  1212
+        # Check that the PK link exists on the rendered form
  1213
+        response = self.client.get('/test_admin/admin/admin_views/collector/1/')
  1214
+        self.assertContains(response, 'name="fancydoodad_set-0-doodad_ptr"')
  1215
+
  1216
+        # Now resave that inline
  1217
+        self.post_data['fancydoodad_set-INITIAL_FORMS'] = "1"
  1218
+        self.post_data['fancydoodad_set-0-doodad_ptr'] = "1"
  1219
+        self.post_data['fancydoodad_set-0-name'] = "Fancy Doodad 1"
  1220
+        response = self.client.post('/test_admin/admin/admin_views/collector/1/', self.post_data)
  1221
+        self.failUnlessEqual(response.status_code, 302)
  1222
+        self.failUnlessEqual(FancyDoodad.objects.count(), 1)
  1223
+        self.failUnlessEqual(FancyDoodad.objects.all()[0].name, "Fancy Doodad 1")
  1224
+
  1225
+        # Now modify that inline
  1226
+        self.post_data['fancydoodad_set-INITIAL_FORMS'] = "1"
  1227
+        self.post_data['fancydoodad_set-0-doodad_ptr'] = "1"
  1228
+        self.post_data['fancydoodad_set-0-name'] = "Fancy Doodad 1 Updated"
  1229
+        response = self.client.post('/test_admin/admin/admin_views/collector/1/', self.post_data)
  1230
+        self.failUnlessEqual(response.status_code, 302)
  1231
+        self.failUnlessEqual(FancyDoodad.objects.count(), 1)
  1232
+        self.failUnlessEqual(FancyDoodad.objects.all()[0].name, "Fancy Doodad 1 Updated")

0 notes on commit 0d930ee

Please sign in to comment.
Something went wrong with that request. Please try again.