Commit 04e6542b authored by Claude Paroz's avatar Claude Paroz
Browse files

Fixed #19423 -- Prevented ModelAdmin sharing widgets due to formfield_overrides

Thanks joebuyer at manycycles.com for the report and Simon Charette
for the review.
parent 61407951
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
import copy
from functools import update_wrapper, partial
import warnings

@@ -130,7 +131,7 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)):
        # passed to formfield_for_dbfield override the defaults.
        for klass in db_field.__class__.mro():
            if klass in self.formfield_overrides:
                kwargs = dict(self.formfield_overrides[klass], **kwargs)
                kwargs = dict(copy.deepcopy(self.formfield_overrides[klass]), **kwargs)
                return db_field.formfield(**kwargs)

        # For any other type of field, just call its formfield() method.
+1 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ class Member(models.Model):
@python_2_unicode_compatible
class Band(models.Model):
    name = models.CharField(max_length=100)
    style = models.CharField(max_length=20)
    members = models.ManyToManyField(Member)

    def __str__(self):
+18 −1
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@ from django.contrib.admin import widgets
from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
from django.core.files.storage import default_storage
from django.core.files.uploadedfile import SimpleUploadedFile
from django.db.models import DateField
from django.db.models import CharField, DateField
from django.test import TestCase as DjangoTestCase
from django.test.utils import override_settings
from django.utils import translation
@@ -112,6 +112,23 @@ class AdminFormfieldForDBFieldTests(TestCase):
        self.assertFormfield(models.Event, 'start_date', forms.TextInput,
                             formfield_overrides={DateField: {'widget': forms.TextInput}})

    def testFormfieldOverridesWidgetInstances(self):
        """
        Test that widget instances in formfield_overrides are not shared between
        different fields. (#19423)
        """
        class BandAdmin(admin.ModelAdmin):
            formfield_overrides = {
                CharField: {'widget': forms.TextInput(attrs={'size':'10'})}
            }
        ma = BandAdmin(models.Band, admin.site)
        f1 = ma.formfield_for_dbfield(models.Band._meta.get_field('name'), request=None)
        f2 = ma.formfield_for_dbfield(models.Band._meta.get_field('style'), request=None)
        self.assertNotEqual(f1.widget, f2.widget)
        self.assertEqual(f1.widget.attrs['maxlength'], '100')
        self.assertEqual(f2.widget.attrs['maxlength'], '20')
        self.assertEqual(f2.widget.attrs['size'], '10')

    def testFieldWithChoices(self):
        self.assertFormfield(models.Member, 'gender', forms.Select)