Kaydet (Commit) 63d425c6 authored tarafından Tim Graham's avatar Tim Graham

[2.0.x] Fixed #28871 -- Fixed initialization of autocomplete widgets in "Add another" inlines.

Also allowed autocomplete widgets to work on AdminSites with a name other
than 'admin'.

Backport of 81057645 from master
üst 31d318d1
...@@ -220,7 +220,7 @@ class BaseModelAdmin(metaclass=forms.MediaDefiningClass): ...@@ -220,7 +220,7 @@ class BaseModelAdmin(metaclass=forms.MediaDefiningClass):
db = kwargs.get('using') db = kwargs.get('using')
if db_field.name in self.get_autocomplete_fields(request): if db_field.name in self.get_autocomplete_fields(request):
kwargs['widget'] = AutocompleteSelect(db_field.remote_field, using=db) kwargs['widget'] = AutocompleteSelect(db_field.remote_field, self.admin_site, using=db)
elif db_field.name in self.raw_id_fields: elif db_field.name in self.raw_id_fields:
kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.remote_field, self.admin_site, using=db) kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.remote_field, self.admin_site, using=db)
elif db_field.name in self.radio_fields: elif db_field.name in self.radio_fields:
...@@ -248,7 +248,7 @@ class BaseModelAdmin(metaclass=forms.MediaDefiningClass): ...@@ -248,7 +248,7 @@ class BaseModelAdmin(metaclass=forms.MediaDefiningClass):
autocomplete_fields = self.get_autocomplete_fields(request) autocomplete_fields = self.get_autocomplete_fields(request)
if db_field.name in autocomplete_fields: if db_field.name in autocomplete_fields:
kwargs['widget'] = AutocompleteSelectMultiple(db_field.remote_field, using=db) kwargs['widget'] = AutocompleteSelectMultiple(db_field.remote_field, self.admin_site, using=db)
elif db_field.name in self.raw_id_fields: elif db_field.name in self.raw_id_fields:
kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.remote_field, self.admin_site, using=db) kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.remote_field, self.admin_site, using=db)
elif db_field.name in list(self.filter_vertical) + list(self.filter_horizontal): elif db_field.name in list(self.filter_vertical) + list(self.filter_horizontal):
......
...@@ -24,15 +24,14 @@ ...@@ -24,15 +24,14 @@
}; };
$(function() { $(function() {
$('.admin-autocomplete').djangoAdminSelect2(); // Initialize all autocomplete widgets except the one in the template
// form used when a new formset is added.
$('.admin-autocomplete').not('[name*=__prefix__]').djangoAdminSelect2();
}); });
$(document).on('formset:added', (function() { $(document).on('formset:added', (function() {
return function(event, $newFormset) { return function(event, $newFormset) {
var $widget = $newFormset.find('.admin-autocomplete'); return $newFormset.find('.admin-autocomplete').djangoAdminSelect2();
// Exclude already initialized Select2 inputs.
$widget = $widget.not('.select2-hidden-accessible');
return init($widget);
}; };
})(this)); })(this));
}(django.jQuery)); }(django.jQuery));
...@@ -400,10 +400,11 @@ class AutocompleteMixin: ...@@ -400,10 +400,11 @@ class AutocompleteMixin:
Renders the necessary data attributes for select2 and adds the static form Renders the necessary data attributes for select2 and adds the static form
media. media.
""" """
url_name = 'admin:%s_%s_autocomplete' url_name = '%s:%s_%s_autocomplete'
def __init__(self, rel, attrs=None, choices=(), using=None): def __init__(self, rel, admin_site, attrs=None, choices=(), using=None):
self.rel = rel self.rel = rel
self.admin_site = admin_site
self.db = using self.db = using
self.choices = choices self.choices = choices
if attrs is not None: if attrs is not None:
...@@ -413,7 +414,7 @@ class AutocompleteMixin: ...@@ -413,7 +414,7 @@ class AutocompleteMixin:
def get_url(self): def get_url(self):
model = self.rel.model model = self.rel.model
return reverse(self.url_name % (model._meta.app_label, model._meta.model_name)) return reverse(self.url_name % (self.admin_site.name, model._meta.app_label, model._meta.model_name))
def build_attrs(self, base_attrs, extra_attrs=None): def build_attrs(self, base_attrs, extra_attrs=None):
""" """
......
...@@ -17,6 +17,7 @@ PAGINATOR_SIZE = AutocompleteJsonView.paginate_by ...@@ -17,6 +17,7 @@ PAGINATOR_SIZE = AutocompleteJsonView.paginate_by
class AuthorAdmin(admin.ModelAdmin): class AuthorAdmin(admin.ModelAdmin):
ordering = ['id']
search_fields = ['id'] search_fields = ['id']
...@@ -229,3 +230,23 @@ class SeleniumTests(AdminSeleniumTestCase): ...@@ -229,3 +230,23 @@ class SeleniumTests(AdminSeleniumTestCase):
search.send_keys(Keys.RETURN) search.send_keys(Keys.RETURN)
select = Select(self.selenium.find_element_by_id('id_related_questions')) select = Select(self.selenium.find_element_by_id('id_related_questions'))
self.assertEqual(len(select.all_selected_options), 2) self.assertEqual(len(select.all_selected_options), 2)
def test_inline_add_another_widgets(self):
def assertNoResults(row):
elem = row.find_element_by_css_selector('.select2-selection')
elem.click() # Open the autocomplete dropdown.
results = self.selenium.find_element_by_css_selector('.select2-results')
self.assertTrue(results.is_displayed())
option = self.selenium.find_element_by_css_selector('.select2-results__option')
self.assertEqual(option.text, 'No results found')
# Autocomplete works in rows present when the page loads.
self.selenium.get(self.live_server_url + reverse('autocomplete_admin:admin_views_book_add'))
rows = self.selenium.find_elements_by_css_selector('.dynamic-authorship_set')
self.assertEqual(len(rows), 3)
assertNoResults(rows[0])
# Autocomplete works in rows added using the "Add another" button.
self.selenium.find_element_by_link_text('Add another Authorship').click()
rows = self.selenium.find_elements_by_css_selector('.dynamic-authorship_set')
self.assertEqual(len(rows), 4)
assertNoResults(rows[-1])
from django import forms from django import forms
from django.contrib import admin
from django.contrib.admin.widgets import AutocompleteSelect from django.contrib.admin.widgets import AutocompleteSelect
from django.forms import ModelChoiceField from django.forms import ModelChoiceField
from django.test import TestCase, override_settings from django.test import TestCase, override_settings
...@@ -14,10 +15,12 @@ class AlbumForm(forms.ModelForm): ...@@ -14,10 +15,12 @@ class AlbumForm(forms.ModelForm):
widgets = { widgets = {
'band': AutocompleteSelect( 'band': AutocompleteSelect(
Album._meta.get_field('band').remote_field, Album._meta.get_field('band').remote_field,
admin.site,
attrs={'class': 'my-class'}, attrs={'class': 'my-class'},
), ),
'featuring': AutocompleteSelect( 'featuring': AutocompleteSelect(
Album._meta.get_field('featuring').remote_field, Album._meta.get_field('featuring').remote_field,
admin.site,
) )
} }
...@@ -25,7 +28,7 @@ class AlbumForm(forms.ModelForm): ...@@ -25,7 +28,7 @@ class AlbumForm(forms.ModelForm):
class NotRequiredBandForm(forms.Form): class NotRequiredBandForm(forms.Form):
band = ModelChoiceField( band = ModelChoiceField(
queryset=Album.objects.all(), queryset=Album.objects.all(),
widget=AutocompleteSelect(Album._meta.get_field('band').remote_field), widget=AutocompleteSelect(Album._meta.get_field('band').remote_field, admin.site),
required=False, required=False,
) )
...@@ -33,7 +36,7 @@ class NotRequiredBandForm(forms.Form): ...@@ -33,7 +36,7 @@ class NotRequiredBandForm(forms.Form):
class RequiredBandForm(forms.Form): class RequiredBandForm(forms.Form):
band = ModelChoiceField( band = ModelChoiceField(
queryset=Album.objects.all(), queryset=Album.objects.all(),
widget=AutocompleteSelect(Album._meta.get_field('band').remote_field), widget=AutocompleteSelect(Album._meta.get_field('band').remote_field, admin.site),
required=True, required=True,
) )
...@@ -68,7 +71,7 @@ class AutocompleteMixinTests(TestCase): ...@@ -68,7 +71,7 @@ class AutocompleteMixinTests(TestCase):
def test_get_url(self): def test_get_url(self):
rel = Album._meta.get_field('band').remote_field rel = Album._meta.get_field('band').remote_field
w = AutocompleteSelect(rel) w = AutocompleteSelect(rel, admin.site)
url = w.get_url() url = w.get_url()
self.assertEqual(url, '/admin_widgets/band/autocomplete/') self.assertEqual(url, '/admin_widgets/band/autocomplete/')
...@@ -130,4 +133,4 @@ class AutocompleteMixinTests(TestCase): ...@@ -130,4 +133,4 @@ class AutocompleteMixinTests(TestCase):
else: else:
expected_files = base_files expected_files = base_files
with translation.override(lang): with translation.override(lang):
self.assertEqual(AutocompleteSelect(rel).media._js, expected_files) self.assertEqual(AutocompleteSelect(rel, admin.site).media._js, expected_files)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment