diff --git a/django/contrib/contenttypes/generic.py b/django/contrib/contenttypes/generic.py index 0d542a4a4e..2a9f4d3ac6 100644 --- a/django/contrib/contenttypes/generic.py +++ b/django/contrib/contenttypes/generic.py @@ -297,11 +297,7 @@ class BaseGenericInlineFormSet(BaseModelFormSet): # Avoid a circular import. from django.contrib.contenttypes.models import ContentType opts = self.model._meta - if instance is None: - self.instance = self.model() - else: - self.instance = instance - self.save_as_new = save_as_new + self.instance = instance self.rel_name = '-'.join(( opts.app_label, opts.object_name.lower(), self.ct_field.name, self.ct_fk_field.name, @@ -328,19 +324,15 @@ class BaseGenericInlineFormSet(BaseModelFormSet): )) get_default_prefix = classmethod(get_default_prefix) - def _construct_form(self, i, **kwargs): + def save_new(self, form, commit=True): # Avoid a circular import. from django.contrib.contenttypes.models import ContentType - form = super(BaseGenericInlineFormSet, self)._construct_form(i, **kwargs) - if self.save_as_new: - # Remove the key from the form's data, we are only creating new instances. - form.data[form.add_prefix(self.ct_fk_field.name)] = None - form.data[form.add_prefix(self.ct_field.name)] = None - - # Set the GenericForeignKey value here so that the form can do its validation. - setattr(form.instance, self.ct_fk_field.attname, self.instance.pk) - setattr(form.instance, self.ct_field.attname, ContentType.objects.get_for_model(self.instance).pk) - return form + kwargs = { + self.ct_field.get_attname(): ContentType.objects.get_for_model(self.instance).pk, + self.ct_fk_field.get_attname(): self.instance.pk, + } + new_obj = self.model(**kwargs) + return save_instance(form, new_obj, commit=commit) def generic_inlineformset_factory(model, form=ModelForm, formset=BaseGenericInlineFormSet, diff --git a/tests/regressiontests/generic_inline_admin/models.py b/tests/regressiontests/generic_inline_admin/models.py index 9f1bbadd3e..2925b7a801 100644 --- a/tests/regressiontests/generic_inline_admin/models.py +++ b/tests/regressiontests/generic_inline_admin/models.py @@ -72,3 +72,24 @@ class MediaExcludeInline(generic.GenericTabularInline): admin.site.register(EpisodeExclude, inlines=[MediaExcludeInline]) +# +# Generic inline with unique_together +# + +class PhoneNumber(models.Model): + content_type = models.ForeignKey(ContentType) + object_id = models.PositiveIntegerField() + content_object = generic.GenericForeignKey('content_type', 'object_id') + phone_number = models.CharField(max_length=30) + + class Meta: + unique_together = (('content_type', 'object_id', 'phone_number',),) + +class Contact(models.Model): + name = models.CharField(max_length=50) + phone_numbers = generic.GenericRelation(PhoneNumber) + +class PhoneNumberInline(generic.GenericTabularInline): + model = PhoneNumber + +admin.site.register(Contact, inlines=[PhoneNumberInline]) diff --git a/tests/regressiontests/generic_inline_admin/tests.py b/tests/regressiontests/generic_inline_admin/tests.py index 0cf1f4ea69..21704cd8de 100644 --- a/tests/regressiontests/generic_inline_admin/tests.py +++ b/tests/regressiontests/generic_inline_admin/tests.py @@ -176,3 +176,25 @@ class GenericInlineAdminParametersTest(TestCase): response = self.client.get('/generic_inline_admin/admin/generic_inline_admin/episodeexclude/%s/' % e.pk) formset = response.context['inline_admin_formsets'][0].formset self.failIf('url' in formset.forms[0], 'The formset has excluded "url" field.') + +class GenericInlineAdminWithUniqueTogetherTest(TestCase): + fixtures = ['users.xml'] + + def setUp(self): + self.client.login(username='super', password='secret') + + def tearDown(self): + self.client.logout() + + def testAdd(self): + post_data = { + "name": u"John Doe", + # inline data + "generic_inline_admin-phonenumber-content_type-object_id-TOTAL_FORMS": u"1", + "generic_inline_admin-phonenumber-content_type-object_id-INITIAL_FORMS": u"0", + "generic_inline_admin-phonenumber-content_type-object_id-0-id": "", + "generic_inline_admin-phonenumber-content_type-object_id-0-phone_number": "555-555-5555", + } + response = self.client.get('/generic_inline_admin/admin/generic_inline_admin/contact/add/') + response = self.client.post('/generic_inline_admin/admin/generic_inline_admin/contact/add/', post_data) + self.failUnlessEqual(response.status_code, 302) # redirect somewhere