From a5c8a6ce19eabd96bf3b8c7bb4fb487f53928f3b Mon Sep 17 00:00:00 2001
From: David Sanders <dsanders11@ucsbalum.com>
Date: Wed, 30 Mar 2016 04:01:15 -0700
Subject: [PATCH] Fixed #21332, #26538 -- Fixed inconsistent and duplicate form
 fields on inline formsets.

---
 django/forms/models.py         | 14 +++++++-------
 tests/inline_formsets/tests.py | 31 ++++++++++++++++++++++++++++++-
 2 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/django/forms/models.py b/django/forms/models.py
index 4ed8b746d9..7ba98e1e26 100644
--- a/django/forms/models.py
+++ b/django/forms/models.py
@@ -889,6 +889,13 @@ class BaseInlineFormSet(BaseModelFormSet):
         super(BaseInlineFormSet, self).__init__(data, files, prefix=prefix,
                                                 queryset=qs, **kwargs)
 
+        # Add the generated field to form._meta.fields if it's defined to make
+        # sure validation isn't skipped on that field.
+        if self.form._meta.fields and self.fk.name not in self.form._meta.fields:
+            if isinstance(self.form._meta.fields, tuple):
+                self.form._meta.fields = list(self.form._meta.fields)
+            self.form._meta.fields.append(self.fk.name)
+
     def initial_form_count(self):
         if self.save_as_new:
             return 0
@@ -960,13 +967,6 @@ class BaseInlineFormSet(BaseModelFormSet):
 
         form.fields[name] = InlineForeignKeyField(self.instance, **kwargs)
 
-        # Add the generated field to form._meta.fields if it's defined to make
-        # sure validation isn't skipped on that field.
-        if form._meta.fields:
-            if isinstance(form._meta.fields, tuple):
-                form._meta.fields = list(form._meta.fields)
-            form._meta.fields.append(self.fk.name)
-
     def get_unique_error_message(self, unique_check):
         unique_check = [field for field in unique_check if field != self.fk.name]
         return super(BaseInlineFormSet, self).get_unique_error_message(unique_check)
diff --git a/tests/inline_formsets/tests.py b/tests/inline_formsets/tests.py
index f516ae8c7b..84faa08894 100644
--- a/tests/inline_formsets/tests.py
+++ b/tests/inline_formsets/tests.py
@@ -1,6 +1,6 @@
 from __future__ import unicode_literals
 
-from django.forms.models import inlineformset_factory
+from django.forms.models import ModelForm, inlineformset_factory
 from django.test import TestCase, skipUnlessDBFeature
 from django.utils import six
 
@@ -176,3 +176,32 @@ class InlineFormsetFactoryTest(TestCase):
         formset = PoemFormSet(data, instance=poet)
         self.assertFalse(formset.is_valid())
         self.assertEqual(formset.non_form_errors(), ['Please correct the duplicate data for name.'])
+
+    def test_fk_not_duplicated_in_form_fields(self):
+        """
+        A foreign key name isn't duplicated in form._meta fields (#21332).
+        """
+        poet = Poet.objects.create(name='test')
+        poet.poem_set.create(name='first test poem')
+        poet.poem_set.create(name='second test poem')
+        poet.poem_set.create(name='third test poem')
+        PoemFormSet = inlineformset_factory(Poet, Poem, fields=('name',), extra=0)
+        formset = PoemFormSet(None, instance=poet)
+        self.assertEqual(len(formset.forms), 3)
+        self.assertEqual(['name', 'poet'], PoemFormSet.form._meta.fields)
+
+    def test_fk_in_all_formset_forms(self):
+        """
+        A foreign key field is in Meta for all forms in the formset (#26538).
+        """
+        class PoemModelForm(ModelForm):
+            def __init__(self, *args, **kwargs):
+                assert 'poet' in self._meta.fields
+                super(PoemModelForm, self).__init__(*args, **kwargs)
+
+        poet = Poet.objects.create(name='test')
+        poet.poem_set.create(name='first test poem')
+        poet.poem_set.create(name='second test poem')
+        PoemFormSet = inlineformset_factory(Poet, Poem, form=PoemModelForm, fields=('name',), extra=0)
+        formset = PoemFormSet(None, instance=poet)
+        formset.forms  # Trigger form instantiation to run the assert above.