[1.5.x] Fixed #19423 -- Prevented ModelAdmin sharing widgets due to formfield_overrides

Thanks joebuyer at manycycles.com for the report and Simon Charette
for the review.
Backport of 04e6542b5 from master.
This commit is contained in:
Claude Paroz 2012-12-08 12:41:11 +01:00
parent 9af9cdb3eb
commit fa54604606
3 changed files with 21 additions and 2 deletions

View File

@ -1,3 +1,4 @@
import copy
from functools import update_wrapper, partial from functools import update_wrapper, partial
import warnings import warnings
@ -130,7 +131,7 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)):
# passed to formfield_for_dbfield override the defaults. # passed to formfield_for_dbfield override the defaults.
for klass in db_field.__class__.mro(): for klass in db_field.__class__.mro():
if klass in self.formfield_overrides: 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) return db_field.formfield(**kwargs)
# For any other type of field, just call its formfield() method. # For any other type of field, just call its formfield() method.

View File

@ -20,6 +20,7 @@ class Member(models.Model):
@python_2_unicode_compatible @python_2_unicode_compatible
class Band(models.Model): class Band(models.Model):
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
style = models.CharField(max_length=20)
members = models.ManyToManyField(Member) members = models.ManyToManyField(Member)
def __str__(self): def __str__(self):

View File

@ -10,7 +10,7 @@ from django.contrib.admin import widgets
from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
from django.core.files.storage import default_storage from django.core.files.storage import default_storage
from django.core.files.uploadedfile import SimpleUploadedFile 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 import TestCase as DjangoTestCase
from django.test.utils import override_settings from django.test.utils import override_settings
from django.utils import translation from django.utils import translation
@ -112,6 +112,23 @@ class AdminFormfieldForDBFieldTests(TestCase):
self.assertFormfield(models.Event, 'start_date', forms.TextInput, self.assertFormfield(models.Event, 'start_date', forms.TextInput,
formfield_overrides={DateField: {'widget': 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): def testFieldWithChoices(self):
self.assertFormfield(models.Member, 'gender', forms.Select) self.assertFormfield(models.Member, 'gender', forms.Select)