From 685582940bf4dfb5caf09bd8a73e6f74745190a8 Mon Sep 17 00:00:00 2001 From: Tim Graham Date: Tue, 8 Jul 2014 15:58:14 -0400 Subject: [PATCH] [1.6.x] Fixed #13794 -- Fixed to_field usage in BaseInlineFormSet. Thanks sebastien at clarisys.fr for the report and gautier for the patch. Backport of 5e2c4a4bd1 from master --- django/forms/models.py | 6 ++++- tests/model_formsets_regress/models.py | 9 +++++++ tests/model_formsets_regress/tests.py | 36 +++++++++++++++++++++++++- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/django/forms/models.py b/django/forms/models.py index 4e92e0ec42..bf28d95414 100644 --- a/django/forms/models.py +++ b/django/forms/models.py @@ -855,7 +855,11 @@ class BaseInlineFormSet(BaseModelFormSet): form.data[form.add_prefix(self.fk.name)] = None # Set the fk value here so that the form can do its validation. - setattr(form.instance, self.fk.get_attname(), self.instance.pk) + fk_value = self.instance.pk + if self.fk.rel.field_name != self.fk.rel.to._meta.pk.name: + fk_value = getattr(self.instance, self.fk.rel.field_name) + fk_value = getattr(fk_value, 'pk', fk_value) + setattr(form.instance, self.fk.get_attname(), fk_value) return form @classmethod diff --git a/tests/model_formsets_regress/models.py b/tests/model_formsets_regress/models.py index f94ad51929..f907207f20 100644 --- a/tests/model_formsets_regress/models.py +++ b/tests/model_formsets_regress/models.py @@ -10,6 +10,15 @@ class UserSite(models.Model): user = models.ForeignKey(User, to_field="username") data = models.IntegerField() +class UserProfile(models.Model): + user = models.ForeignKey(User, unique=True, to_field="username") + about = models.TextField() + +class ProfileNetwork(models.Model): + profile = models.ForeignKey(UserProfile, to_field="user") + network = models.IntegerField() + identifier = models.IntegerField() + class Place(models.Model): name = models.CharField(max_length=50) diff --git a/tests/model_formsets_regress/tests.py b/tests/model_formsets_regress/tests.py index 179f79fbcb..90c2f02727 100644 --- a/tests/model_formsets_regress/tests.py +++ b/tests/model_formsets_regress/tests.py @@ -7,7 +7,10 @@ from django.forms.models import modelform_factory, inlineformset_factory, modelf from django.test import TestCase from django.utils import six -from .models import User, UserSite, Restaurant, Manager, Network, Host +from .models import ( + User, UserSite, UserProfile, ProfileNetwork, Restaurant, Manager, Network, + Host, +) class InlineFormsetTests(TestCase): @@ -154,6 +157,37 @@ class InlineFormsetTests(TestCase): else: self.fail('Errors found on formset:%s' % form_set.errors) + def test_inline_model_with_to_field(self): + """ + #13794 --- An inline model with a to_field of a formset with instance + has working relations. + """ + FormSet = inlineformset_factory(User, UserSite, exclude=('is_superuser',)) + + user = User.objects.create(username="guido", serial=1337) + UserSite.objects.create(user=user, data=10) + formset = FormSet(instance=user) + + # Testing the inline model's relation + self.assertEqual(formset[0].instance.user_id, "guido") + + def test_inline_model_with_to_field_to_rel(self): + """ + #13794 --- An inline model with a to_field to a related field of a + formset with instance has working relations. + """ + FormSet = inlineformset_factory(UserProfile, ProfileNetwork, exclude=[]) + + user = User.objects.create(username="guido", serial=1337, pk=1) + self.assertEqual(user.pk, 1) + profile = UserProfile.objects.create(user=user, about="about", pk=2) + self.assertEqual(profile.pk, 2) + ProfileNetwork.objects.create(profile=profile, network=10, identifier=10) + formset = FormSet(instance=profile) + + # Testing the inline model's relation + self.assertEqual(formset[0].instance.profile_id, 1) + def test_formset_with_none_instance(self): "A formset with instance=None can be created. Regression for #11872" Form = modelform_factory(User, fields="__all__")