diff --git a/django/contrib/admin/helpers.py b/django/contrib/admin/helpers.py
index e969a41390..aaa2e304ce 100644
--- a/django/contrib/admin/helpers.py
+++ b/django/contrib/admin/helpers.py
@@ -108,8 +108,9 @@ class InlineAdminFormSet(object):
yield InlineAdminForm(self.formset, form, self.fieldsets, self.opts.prepopulated_fields, None)
def fields(self):
+ fk = getattr(self.formset, "fk", None)
for field_name in flatten_fieldsets(self.fieldsets):
- if self.formset.fk.name == field_name:
+ if fk and fk.name == field_name:
continue
yield self.formset.form.base_fields[field_name]
@@ -150,7 +151,11 @@ class InlineAdminForm(AdminForm):
return AdminField(self.form, self.formset._pk_field.name, False)
def fk_field(self):
- return AdminField(self.form, self.formset.fk.name, False)
+ fk = getattr(self.formset, "fk", None)
+ if fk:
+ return AdminField(self.form, fk.name, False)
+ else:
+ return ""
def deletion_field(self):
from django.forms.formsets import DELETION_FIELD_NAME
@@ -166,8 +171,9 @@ class InlineFieldset(Fieldset):
super(InlineFieldset, self).__init__(*args, **kwargs)
def __iter__(self):
+ fk = getattr(self.formset, "fk", None)
for field in self.fields:
- if self.formset.fk.name == field:
+ if fk and fk.name == field:
continue
yield Fieldline(self.form, field)
diff --git a/tests/regressiontests/generic_inline_admin/__init__.py b/tests/regressiontests/generic_inline_admin/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/regressiontests/generic_inline_admin/fixtures/model-data.xml b/tests/regressiontests/generic_inline_admin/fixtures/model-data.xml
new file mode 100644
index 0000000000..a629208d2d
--- /dev/null
+++ b/tests/regressiontests/generic_inline_admin/fixtures/model-data.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/regressiontests/generic_inline_admin/fixtures/users.xml b/tests/regressiontests/generic_inline_admin/fixtures/users.xml
new file mode 100644
index 0000000000..6cf441f01e
--- /dev/null
+++ b/tests/regressiontests/generic_inline_admin/fixtures/users.xml
@@ -0,0 +1,17 @@
+
+
+
+
\ No newline at end of file
diff --git a/tests/regressiontests/generic_inline_admin/models.py b/tests/regressiontests/generic_inline_admin/models.py
new file mode 100644
index 0000000000..6e9fbebabb
--- /dev/null
+++ b/tests/regressiontests/generic_inline_admin/models.py
@@ -0,0 +1,30 @@
+from django.db import models
+from django.contrib import admin
+from django.contrib.contenttypes import generic
+from django.contrib.contenttypes.models import ContentType
+
+class Episode(models.Model):
+ name = models.CharField(max_length=100)
+
+class Media(models.Model):
+ """
+ Media that can associated to any object.
+ """
+ content_type = models.ForeignKey(ContentType)
+ object_id = models.PositiveIntegerField()
+ content_object = generic.GenericForeignKey()
+ url = models.URLField(verify_exists=False)
+
+ def __unicode__(self):
+ return self.url
+
+class MediaInline(generic.GenericTabularInline):
+ model = Media
+ extra = 1
+
+class EpisodeAdmin(admin.ModelAdmin):
+ inlines = [
+ MediaInline,
+ ]
+
+admin.site.register(Episode, EpisodeAdmin)
diff --git a/tests/regressiontests/generic_inline_admin/tests.py b/tests/regressiontests/generic_inline_admin/tests.py
new file mode 100644
index 0000000000..f2953fee54
--- /dev/null
+++ b/tests/regressiontests/generic_inline_admin/tests.py
@@ -0,0 +1,66 @@
+# coding: utf-8
+
+from django.test import TestCase
+from django.conf import settings
+
+# local test models
+from models import Episode, Media
+
+class GenericAdminViewTest(TestCase):
+ fixtures = ['users.xml', 'model-data.xml']
+
+ def setUp(self):
+ # set TEMPLATE_DEBUG to True to ensure {% include %} will raise
+ # exceptions since that is how inlines are rendered and #9498 will
+ # bubble up if it is an issue.
+ self.original_template_debug = settings.TEMPLATE_DEBUG
+ settings.TEMPLATE_DEBUG = True
+ self.client.login(username='super', password='secret')
+
+ def tearDown(self):
+ self.client.logout()
+ settings.TEMPLATE_DEBUG = self.original_template_debug
+
+ def testBasicAddGet(self):
+ """
+ A smoke test to ensure GET on the add_view works.
+ """
+ response = self.client.get('/generic_inline_admin/admin/generic_inline_admin/episode/add/')
+ self.failUnlessEqual(response.status_code, 200)
+
+ def testBasicEditGet(self):
+ """
+ A smoke test to ensure GET on the change_view works.
+ """
+ response = self.client.get('/generic_inline_admin/admin/generic_inline_admin/episode/1/')
+ self.failUnlessEqual(response.status_code, 200)
+
+ def testBasicAddPost(self):
+ """
+ A smoke test to ensure POST on add_view works.
+ """
+ post_data = {
+ "name": u"This Week in Django",
+ # inline data
+ "generic_inline_admin-media-content_type-object_id-TOTAL_FORMS": u"1",
+ "generic_inline_admin-media-content_type-object_id-INITIAL_FORMS": u"0",
+ }
+ response = self.client.post('/generic_inline_admin/admin/generic_inline_admin/episode/add/', post_data)
+ self.failUnlessEqual(response.status_code, 302) # redirect somewhere
+
+ def testBasicEditPost(self):
+ """
+ A smoke test to ensure POST on edit_view works.
+ """
+ post_data = {
+ "name": u"This Week in Django",
+ # inline data
+ "generic_inline_admin-media-content_type-object_id-TOTAL_FORMS": u"2",
+ "generic_inline_admin-media-content_type-object_id-INITIAL_FORMS": u"1",
+ "generic_inline_admin-media-content_type-object_id-0-id": u"1",
+ "generic_inline_admin-media-content_type-object_id-0-url": u"http://example.com/podcast.mp3",
+ "generic_inline_admin-media-content_type-object_id-1-id": u"",
+ "generic_inline_admin-media-content_type-object_id-1-url": u"",
+ }
+ response = self.client.post('/generic_inline_admin/admin/generic_inline_admin/episode/1/', post_data)
+ self.failUnlessEqual(response.status_code, 302) # redirect somewhere
diff --git a/tests/regressiontests/generic_inline_admin/urls.py b/tests/regressiontests/generic_inline_admin/urls.py
new file mode 100644
index 0000000000..04d68cd26c
--- /dev/null
+++ b/tests/regressiontests/generic_inline_admin/urls.py
@@ -0,0 +1,6 @@
+from django.conf.urls.defaults import *
+from django.contrib import admin
+
+urlpatterns = patterns('',
+ (r'^admin/(.*)', admin.site.root),
+)
diff --git a/tests/urls.py b/tests/urls.py
index a8dc583aa1..b6c9d6e030 100644
--- a/tests/urls.py
+++ b/tests/urls.py
@@ -23,6 +23,7 @@ urlpatterns = patterns('',
# admin view tests
(r'^test_admin/', include('regressiontests.admin_views.urls')),
+ (r'^generic_inline_admin/', include('regressiontests.generic_inline_admin.urls')),
(r'^utils/', include('regressiontests.utils.urls')),