Loading django/contrib/admin/options.py +5 −2 Original line number Diff line number Diff line Loading @@ -117,8 +117,11 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)): return self.checks_class().check(self, **kwargs) def __init__(self): overrides = FORMFIELD_FOR_DBFIELD_DEFAULTS.copy() overrides.update(self.formfield_overrides) # Merge FORMFIELD_FOR_DBFIELD_DEFAULTS with the formfield_overrides # rather than simply overwriting. overrides = copy.deepcopy(FORMFIELD_FOR_DBFIELD_DEFAULTS) for k, v in self.formfield_overrides.items(): overrides.setdefault(k, {}).update(v) self.formfield_overrides = overrides def formfield_for_dbfield(self, db_field, request, **kwargs): Loading tests/admin_widgets/tests.py +23 −1 Original line number Diff line number Diff line Loading @@ -15,7 +15,7 @@ from django.contrib.admin.tests import AdminSeleniumTestCase from django.contrib.auth.models import User from django.core.files.storage import default_storage from django.core.files.uploadedfile import SimpleUploadedFile from django.db.models import CharField, DateField from django.db.models import CharField, DateField, DateTimeField from django.test import SimpleTestCase, TestCase, override_settings from django.urls import reverse from django.utils import six, translation Loading Loading @@ -150,6 +150,28 @@ class AdminFormfieldForDBFieldTests(SimpleTestCase): self.assertEqual(f2.widget.attrs['maxlength'], '20') self.assertEqual(f2.widget.attrs['size'], '10') def test_formfield_overrides_for_datetime_field(self): """ Overriding the widget for DateTimeField doesn't overrides the default form_class for that field (#26449). """ class MemberAdmin(admin.ModelAdmin): formfield_overrides = {DateTimeField: {'widget': widgets.AdminSplitDateTime}} ma = MemberAdmin(models.Member, admin.site) f1 = ma.formfield_for_dbfield(models.Member._meta.get_field('birthdate'), request=None) self.assertIsInstance(f1.widget, widgets.AdminSplitDateTime) self.assertIsInstance(f1, forms.SplitDateTimeField) def test_formfield_overrides_for_custom_field(self): """ formfield_overrides works for a custom field class. """ class AlbumAdmin(admin.ModelAdmin): formfield_overrides = {models.MyFileField: {'widget': forms.TextInput()}} ma = AlbumAdmin(models.Member, admin.site) f1 = ma.formfield_for_dbfield(models.Album._meta.get_field('backside_art'), request=None) self.assertIsInstance(f1.widget, forms.TextInput) def test_field_with_choices(self): self.assertFormfield(models.Member, 'gender', forms.Select) Loading Loading
django/contrib/admin/options.py +5 −2 Original line number Diff line number Diff line Loading @@ -117,8 +117,11 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)): return self.checks_class().check(self, **kwargs) def __init__(self): overrides = FORMFIELD_FOR_DBFIELD_DEFAULTS.copy() overrides.update(self.formfield_overrides) # Merge FORMFIELD_FOR_DBFIELD_DEFAULTS with the formfield_overrides # rather than simply overwriting. overrides = copy.deepcopy(FORMFIELD_FOR_DBFIELD_DEFAULTS) for k, v in self.formfield_overrides.items(): overrides.setdefault(k, {}).update(v) self.formfield_overrides = overrides def formfield_for_dbfield(self, db_field, request, **kwargs): Loading
tests/admin_widgets/tests.py +23 −1 Original line number Diff line number Diff line Loading @@ -15,7 +15,7 @@ from django.contrib.admin.tests import AdminSeleniumTestCase from django.contrib.auth.models import User from django.core.files.storage import default_storage from django.core.files.uploadedfile import SimpleUploadedFile from django.db.models import CharField, DateField from django.db.models import CharField, DateField, DateTimeField from django.test import SimpleTestCase, TestCase, override_settings from django.urls import reverse from django.utils import six, translation Loading Loading @@ -150,6 +150,28 @@ class AdminFormfieldForDBFieldTests(SimpleTestCase): self.assertEqual(f2.widget.attrs['maxlength'], '20') self.assertEqual(f2.widget.attrs['size'], '10') def test_formfield_overrides_for_datetime_field(self): """ Overriding the widget for DateTimeField doesn't overrides the default form_class for that field (#26449). """ class MemberAdmin(admin.ModelAdmin): formfield_overrides = {DateTimeField: {'widget': widgets.AdminSplitDateTime}} ma = MemberAdmin(models.Member, admin.site) f1 = ma.formfield_for_dbfield(models.Member._meta.get_field('birthdate'), request=None) self.assertIsInstance(f1.widget, widgets.AdminSplitDateTime) self.assertIsInstance(f1, forms.SplitDateTimeField) def test_formfield_overrides_for_custom_field(self): """ formfield_overrides works for a custom field class. """ class AlbumAdmin(admin.ModelAdmin): formfield_overrides = {models.MyFileField: {'widget': forms.TextInput()}} ma = AlbumAdmin(models.Member, admin.site) f1 = ma.formfield_for_dbfield(models.Album._meta.get_field('backside_art'), request=None) self.assertIsInstance(f1.widget, forms.TextInput) def test_field_with_choices(self): self.assertFormfield(models.Member, 'gender', forms.Select) Loading