summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author007 <007gzs@gmail.com>2020-04-13 19:04:26 +0800
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-04-15 08:33:40 +0200
commitd51c50d836c5cf8db5566da17963f871be554615 (patch)
treed731ef25e7936a026da50698a216f27e8b870704
parent5b884d45ac5b76234eca614d90c83b347294c332 (diff)
downloaddjango-d51c50d836c5cf8db5566da17963f871be554615.tar.gz
Fixed #31462 -- Allowed overriding autocomplete/raw_id_fields/filter widgets for ManyToManyFields with formfield_overrides.
-rw-r--r--django/contrib/admin/options.py30
-rw-r--r--tests/admin_widgets/tests.py19
2 files changed, 37 insertions, 12 deletions
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index 69a5fbf389..2099d14861 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -249,17 +249,25 @@ class BaseModelAdmin(metaclass=forms.MediaDefiningClass):
return None
db = kwargs.get('using')
- autocomplete_fields = self.get_autocomplete_fields(request)
- if db_field.name in autocomplete_fields:
- kwargs['widget'] = AutocompleteSelectMultiple(db_field.remote_field, self.admin_site, using=db)
- elif db_field.name in self.raw_id_fields:
- kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.remote_field, self.admin_site, using=db)
- elif db_field.name in [*self.filter_vertical, *self.filter_horizontal]:
- kwargs['widget'] = widgets.FilteredSelectMultiple(
- db_field.verbose_name,
- db_field.name in self.filter_vertical
- )
-
+ if 'widget' not in kwargs:
+ autocomplete_fields = self.get_autocomplete_fields(request)
+ if db_field.name in autocomplete_fields:
+ kwargs['widget'] = AutocompleteSelectMultiple(
+ db_field.remote_field,
+ self.admin_site,
+ using=db,
+ )
+ elif db_field.name in self.raw_id_fields:
+ kwargs['widget'] = widgets.ManyToManyRawIdWidget(
+ db_field.remote_field,
+ self.admin_site,
+ using=db,
+ )
+ elif db_field.name in [*self.filter_vertical, *self.filter_horizontal]:
+ kwargs['widget'] = widgets.FilteredSelectMultiple(
+ db_field.verbose_name,
+ db_field.name in self.filter_vertical
+ )
if 'queryset' not in kwargs:
queryset = self.get_field_queryset(db, db_field, request)
if queryset is not None:
diff --git a/tests/admin_widgets/tests.py b/tests/admin_widgets/tests.py
index 719d0d8095..b255d2188a 100644
--- a/tests/admin_widgets/tests.py
+++ b/tests/admin_widgets/tests.py
@@ -14,7 +14,9 @@ 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, DateTimeField, UUIDField
+from django.db.models import (
+ CharField, DateField, DateTimeField, ManyToManyField, UUIDField,
+)
from django.test import SimpleTestCase, TestCase, override_settings
from django.urls import reverse
from django.utils import translation
@@ -138,6 +140,21 @@ class AdminFormfieldForDBFieldTests(SimpleTestCase):
self.assertEqual(f2.widget.attrs['maxlength'], '20')
self.assertEqual(f2.widget.attrs['size'], '10')
+ def test_formfield_overrides_m2m_filter_widget(self):
+ """
+ The autocomplete_fields, raw_id_fields, filter_vertical, and
+ filter_horizontal widgets for ManyToManyFields may be overridden by
+ specifying a widget in formfield_overrides.
+ """
+ class BandAdmin(admin.ModelAdmin):
+ filter_vertical = ['members']
+ formfield_overrides = {
+ ManyToManyField: {'widget': forms.CheckboxSelectMultiple},
+ }
+ ma = BandAdmin(Band, admin.site)
+ field = ma.formfield_for_dbfield(Band._meta.get_field('members'), request=None)
+ self.assertIsInstance(field.widget.widget, forms.CheckboxSelectMultiple)
+
def test_formfield_overrides_for_datetime_field(self):
"""
Overriding the widget for DateTimeField doesn't overrides the default