Skip to content

Commit

Permalink
[1.0.X] Fixed #9498 -- Handle a formset correctly when the foreign ke…
Browse files Browse the repository at this point in the history
…y is not available (for now).

This case pops up with generic foreign key inlines after [9297]. Added tests
to handle future regressions with generic foreign key inlines in the admin.

Thanks markus and danielr for patches.

Backport of [9412] from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.0.X@9413 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
brosner committed Nov 13, 2008
1 parent c8dcbb0 commit f219136
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 3 deletions.
12 changes: 9 additions & 3 deletions django/contrib/admin/helpers.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -108,8 +108,9 @@ def __iter__(self):
yield InlineAdminForm(self.formset, form, self.fieldsets, self.opts.prepopulated_fields, None) yield InlineAdminForm(self.formset, form, self.fieldsets, self.opts.prepopulated_fields, None)


def fields(self): def fields(self):
fk = getattr(self.formset, "fk", None)
for field_name in flatten_fieldsets(self.fieldsets): for field_name in flatten_fieldsets(self.fieldsets):
if self.formset.fk.name == field_name: if fk and fk.name == field_name:
continue continue
yield self.formset.form.base_fields[field_name] yield self.formset.form.base_fields[field_name]


Expand Down Expand Up @@ -150,7 +151,11 @@ def pk_field(self):
return AdminField(self.form, self.formset._pk_field.name, False) return AdminField(self.form, self.formset._pk_field.name, False)


def fk_field(self): 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): def deletion_field(self):
from django.forms.formsets import DELETION_FIELD_NAME from django.forms.formsets import DELETION_FIELD_NAME
Expand All @@ -166,8 +171,9 @@ def __init__(self, formset, *args, **kwargs):
super(InlineFieldset, self).__init__(*args, **kwargs) super(InlineFieldset, self).__init__(*args, **kwargs)


def __iter__(self): def __iter__(self):
fk = getattr(self.formset, "fk", None)
for field in self.fields: for field in self.fields:
if self.formset.fk.name == field: if fk and fk.name == field:
continue continue
yield Fieldline(self.form, field) yield Fieldline(self.form, field)


Expand Down
Empty file.
11 changes: 11 additions & 0 deletions tests/regressiontests/generic_inline_admin/fixtures/model-data.xml
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<django-objects version="1.0">
<object pk="1" model="generic_inline_admin.Episode">
<field type="CharField" name="name">This Week in Django</field>
</object>
<object pk="1" model="generic_inline_admin.Media">
<field type="ForeignKey" name="content_type">13</field>
<field type="PositiveIntegerField" name="object_id">1</field>
<field type="URLField" name="url">http://example.com/podcast.mp3</field>
</object>
</django-objects>
17 changes: 17 additions & 0 deletions tests/regressiontests/generic_inline_admin/fixtures/users.xml
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<django-objects version="1.0">
<object pk="100" model="auth.user">
<field type="CharField" name="username">super</field>
<field type="CharField" name="first_name">Super</field>
<field type="CharField" name="last_name">User</field>
<field type="CharField" name="email">super@example.com</field>
<field type="CharField" name="password">sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158</field>
<field type="BooleanField" name="is_staff">True</field>
<field type="BooleanField" name="is_active">True</field>
<field type="BooleanField" name="is_superuser">True</field>
<field type="DateTimeField" name="last_login">2007-05-30 13:20:10</field>
<field type="DateTimeField" name="date_joined">2007-05-30 13:20:10</field>
<field to="auth.group" name="groups" rel="ManyToManyRel"></field>
<field to="auth.permission" name="user_permissions" rel="ManyToManyRel"></field>
</object>
</django-objects>
30 changes: 30 additions & 0 deletions tests/regressiontests/generic_inline_admin/models.py
Original file line number Original file line Diff line number Diff line change
@@ -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)
66 changes: 66 additions & 0 deletions tests/regressiontests/generic_inline_admin/tests.py
Original file line number Original file line Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions tests/regressiontests/generic_inline_admin/urls.py
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.conf.urls.defaults import *
from django.contrib import admin

urlpatterns = patterns('',
(r'^admin/(.*)', admin.site.root),
)
1 change: 1 addition & 0 deletions tests/urls.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@


# admin view tests # admin view tests
(r'^test_admin/', include('regressiontests.admin_views.urls')), (r'^test_admin/', include('regressiontests.admin_views.urls')),
(r'^generic_inline_admin/', include('regressiontests.generic_inline_admin.urls')),


(r'^utils/', include('regressiontests.utils.urls')), (r'^utils/', include('regressiontests.utils.urls')),


Expand Down

0 comments on commit f219136

Please sign in to comment.