From a097ee32d8364045a950d6a36b19630fc34397f1 Mon Sep 17 00:00:00 2001
From: Simon Charette <charette.s@gmail.com>
Date: Tue, 5 Feb 2013 05:39:35 -0500
Subject: [PATCH] Fixed #17683 -- Make sure `BaseModelFormSet` respects defined
 widgets.

---
 django/forms/models.py                          |  6 +++++-
 .../model_formsets_regress/tests.py             | 17 +++++++++++------
 2 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/django/forms/models.py b/django/forms/models.py
index 837da748149..e2d739fd1a4 100644
--- a/django/forms/models.py
+++ b/django/forms/models.py
@@ -678,7 +678,11 @@ class BaseModelFormSet(BaseFormSet):
             else:
                 qs = self.model._default_manager.get_query_set()
             qs = qs.using(form.instance._state.db)
-            form.fields[self._pk_field.name] = ModelChoiceField(qs, initial=pk_value, required=False, widget=HiddenInput)
+            if form._meta.widgets:
+                widget = form._meta.widgets.get(self._pk_field.name, HiddenInput)
+            else:
+                widget = HiddenInput
+            form.fields[self._pk_field.name] = ModelChoiceField(qs, initial=pk_value, required=False, widget=widget)
         super(BaseModelFormSet, self).add_fields(form, index)
 
 def modelformset_factory(model, form=ModelForm, formfield_callback=None,
diff --git a/tests/regressiontests/model_formsets_regress/tests.py b/tests/regressiontests/model_formsets_regress/tests.py
index 8cadcfc409c..fd35eda854f 100644
--- a/tests/regressiontests/model_formsets_regress/tests.py
+++ b/tests/regressiontests/model_formsets_regress/tests.py
@@ -261,14 +261,17 @@ class FormsetTests(TestCase):
             formset.save()
 
 
-class CustomWidget(forms.CharField):
+class CustomWidget(forms.widgets.TextInput):
     pass
 
 
 class UserSiteForm(forms.ModelForm):
     class Meta:
         model = UserSite
-        widgets = {'data': CustomWidget}
+        widgets = {
+            'id': CustomWidget,
+            'data': CustomWidget,
+        }
 
 
 class Callback(object):
@@ -283,24 +286,27 @@ class Callback(object):
 
 class FormfieldCallbackTests(TestCase):
     """
-    Regression for #13095: Using base forms with widgets
-    defined in Meta should not raise errors.
+    Regression for #13095 and #17683: Using base forms with widgets
+    defined in Meta should not raise errors and BaseModelForm should respect
+    the specified pk widget.
     """
 
     def test_inlineformset_factory_default(self):
         Formset = inlineformset_factory(User, UserSite, form=UserSiteForm)
         form = Formset().forms[0]
+        self.assertTrue(isinstance(form['id'].field.widget, CustomWidget))
         self.assertTrue(isinstance(form['data'].field.widget, CustomWidget))
 
     def test_modelformset_factory_default(self):
         Formset = modelformset_factory(UserSite, form=UserSiteForm)
         form = Formset().forms[0]
+        self.assertTrue(isinstance(form['id'].field.widget, CustomWidget))
         self.assertTrue(isinstance(form['data'].field.widget, CustomWidget))
 
     def assertCallbackCalled(self, callback):
         id_field, user_field, data_field = UserSite._meta.fields
         expected_log = [
-            (id_field, {}),
+            (id_field, {'widget': CustomWidget}),
             (user_field, {}),
             (data_field, {'widget': CustomWidget}),
         ]
@@ -318,7 +324,6 @@ class FormfieldCallbackTests(TestCase):
                              formfield_callback=callback)
         self.assertCallbackCalled(callback)
 
-
 class BaseCustomDeleteFormSet(BaseFormSet):
     """
     A formset mix-in that lets a form decide if it's to be deleted.