mirror of
https://github.com/Hopiu/django-select2.git
synced 2026-03-17 05:50:23 +00:00
dict.setdefault() does not change the default value if called twice. Therefore, defaults need to passed to the super call instead.
This commit is contained in:
parent
898b2e84dd
commit
c15de464d5
4 changed files with 83 additions and 26 deletions
|
|
@ -70,16 +70,18 @@ class Select2Mixin:
|
|||
form media.
|
||||
"""
|
||||
|
||||
def build_attrs(self, *args, **kwargs):
|
||||
def build_attrs(self, base_attrs, extra_attrs=None):
|
||||
"""Add select2 data attributes."""
|
||||
attrs = super(Select2Mixin, self).build_attrs(*args, **kwargs)
|
||||
default_attrs = {'data-minimum-input-length': 0}
|
||||
if self.is_required:
|
||||
attrs.setdefault('data-allow-clear', 'false')
|
||||
default_attrs['data-allow-clear'] = 'false'
|
||||
else:
|
||||
attrs.setdefault('data-allow-clear', 'true')
|
||||
attrs.setdefault('data-placeholder', '')
|
||||
default_attrs['data-allow-clear'] = 'true'
|
||||
default_attrs['data-placeholder'] = ''
|
||||
|
||||
default_attrs.update(base_attrs)
|
||||
attrs = super().build_attrs(default_attrs, extra_attrs=extra_attrs)
|
||||
|
||||
attrs.setdefault('data-minimum-input-length', 0)
|
||||
if 'class' in attrs:
|
||||
attrs['class'] += ' django-select2'
|
||||
else:
|
||||
|
|
@ -120,12 +122,15 @@ class Select2Mixin:
|
|||
class Select2TagMixin:
|
||||
"""Mixin to add select2 tag functionality."""
|
||||
|
||||
def build_attrs(self, *args, **kwargs):
|
||||
def build_attrs(self, base_attrs, extra_attrs=None):
|
||||
"""Add select2's tag attributes."""
|
||||
self.attrs.setdefault('data-minimum-input-length', 1)
|
||||
self.attrs.setdefault('data-tags', 'true')
|
||||
self.attrs.setdefault('data-token-separators', '[",", " "]')
|
||||
return super(Select2TagMixin, self).build_attrs(*args, **kwargs)
|
||||
default_attrs = {
|
||||
'data-minimum-input-length': 1,
|
||||
'data-tags': 'true',
|
||||
'data-token-separators': '[",", " "]'
|
||||
}
|
||||
default_attrs.update(base_attrs)
|
||||
return super().build_attrs(default_attrs, extra_attrs=extra_attrs)
|
||||
|
||||
|
||||
class Select2Widget(Select2Mixin, forms.Select):
|
||||
|
|
@ -226,20 +231,27 @@ class HeavySelect2Mixin:
|
|||
return self.data_url
|
||||
return reverse(self.data_view)
|
||||
|
||||
def build_attrs(self, *args, **kwargs):
|
||||
def build_attrs(self, base_attrs, extra_attrs=None):
|
||||
"""Set select2's AJAX attributes."""
|
||||
attrs = super(HeavySelect2Mixin, self).build_attrs(*args, **kwargs)
|
||||
|
||||
default_attrs = {
|
||||
'data-ajax--url': self.get_url(),
|
||||
'data-ajax--cache': "true",
|
||||
'data-ajax--type': "GET",
|
||||
'data-minimum-input-length': 2,
|
||||
}
|
||||
|
||||
if self.dependent_fields:
|
||||
default_attrs['data-select2-dependent-fields'] = " ".join(self.dependent_fields)
|
||||
|
||||
default_attrs.update(base_attrs)
|
||||
|
||||
attrs = super().build_attrs(default_attrs, extra_attrs=extra_attrs)
|
||||
|
||||
# encrypt instance Id
|
||||
self.widget_id = signing.dumps(id(self))
|
||||
|
||||
attrs['data-field_id'] = self.widget_id
|
||||
attrs.setdefault('data-ajax--url', self.get_url())
|
||||
attrs.setdefault('data-ajax--cache', "true")
|
||||
attrs.setdefault('data-ajax--type', "GET")
|
||||
attrs.setdefault('data-minimum-input-length', 2)
|
||||
if self.dependent_fields:
|
||||
attrs.setdefault('data-select2-dependent-fields', " ".join(self.dependent_fields))
|
||||
|
||||
attrs['class'] += ' django-select2-heavy'
|
||||
return attrs
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import random
|
|||
import string
|
||||
|
||||
import pytest
|
||||
from django.utils.encoding import force_text
|
||||
from selenium import webdriver
|
||||
from selenium.common.exceptions import WebDriverException
|
||||
|
||||
|
|
@ -22,11 +21,11 @@ def random_name(n):
|
|||
@pytest.yield_fixture(scope='session')
|
||||
def driver():
|
||||
chrome_options = webdriver.ChromeOptions()
|
||||
chrome_options.headless = True
|
||||
chrome_options.headless = False
|
||||
try:
|
||||
b = webdriver.Chrome(options=chrome_options)
|
||||
except WebDriverException as e:
|
||||
pytest.skip(force_text(e))
|
||||
pytest.skip(str(e))
|
||||
else:
|
||||
yield b
|
||||
b.quit()
|
||||
|
|
|
|||
|
|
@ -217,12 +217,17 @@ class TestHeavySelect2Mixin(TestSelect2Mixin):
|
|||
driver.find_element_by_css_selector('.select2-results')
|
||||
|
||||
elem1, elem2 = driver.find_elements_by_css_selector('.select2-selection')
|
||||
elem1.click()
|
||||
|
||||
elem1.click()
|
||||
search1 = driver.find_element_by_css_selector('.select2-search__field')
|
||||
search1.send_keys('fo')
|
||||
result1 = WebDriverWait(driver, 60).until(
|
||||
expected_conditions.presence_of_element_located((By.CSS_SELECTOR, '.select2-results li:first-child'))
|
||||
).text
|
||||
|
||||
elem2.click()
|
||||
search2 = driver.find_element_by_css_selector('.select2-search__field')
|
||||
search2.send_keys('fo')
|
||||
result2 = WebDriverWait(driver, 60).until(
|
||||
expected_conditions.presence_of_element_located((By.CSS_SELECTOR, '.select2-results li:first-child'))
|
||||
).text
|
||||
|
|
@ -315,6 +320,37 @@ class TestModelSelect2Mixin(TestHeavySelect2Mixin):
|
|||
widget.queryset = Genre.objects.all()
|
||||
assert isinstance(widget.get_queryset(), QuerySet)
|
||||
|
||||
def test_tag_attrs_Select2Widget(self):
|
||||
widget = Select2Widget()
|
||||
output = widget.render('name', 'value')
|
||||
assert 'data-minimum-input-length="0"' in output
|
||||
|
||||
def test_custom_tag_attrs_Select2Widget(self):
|
||||
widget = Select2Widget(attrs={'data-minimum-input-length': '3'})
|
||||
output = widget.render('name', 'value')
|
||||
assert 'data-minimum-input-length="3"' in output
|
||||
|
||||
def test_tag_attrs_ModelSelect2Widget(self):
|
||||
widget = ModelSelect2Widget(queryset=Genre.objects.all(), search_fields=['title__icontains'])
|
||||
output = widget.render('name', 'value')
|
||||
assert 'data-minimum-input-length="2"' in output
|
||||
|
||||
def test_tag_attrs_ModelSelect2TagWidget(self):
|
||||
widget = ModelSelect2TagWidget(queryset=Genre.objects.all(), search_fields=['title__icontains'])
|
||||
output = widget.render('name', 'value')
|
||||
assert 'data-minimum-input-length="2"' in output
|
||||
|
||||
def test_tag_attrs_HeavySelect2Widget(self):
|
||||
widget = HeavySelect2Widget(data_url='/foo/bar/')
|
||||
output = widget.render('name', 'value')
|
||||
assert 'data-minimum-input-length="2"' in output
|
||||
|
||||
def test_custom_tag_attrs_ModelSelect2Widget(self):
|
||||
widget = ModelSelect2Widget(
|
||||
queryset=Genre.objects.all(), search_fields=['title__icontains'], attrs={'data-minimum-input-length': '3'})
|
||||
output = widget.render('name', 'value')
|
||||
assert 'data-minimum-input-length="3"' in output
|
||||
|
||||
def test_get_search_fields(self):
|
||||
widget = ModelSelect2Widget()
|
||||
with pytest.raises(NotImplementedError):
|
||||
|
|
@ -382,7 +418,7 @@ class TestHeavySelect2TagWidget(TestHeavySelect2Mixin):
|
|||
def test_tag_attrs(self):
|
||||
widget = ModelSelect2TagWidget(queryset=Genre.objects.all(), search_fields=['title__icontains'])
|
||||
output = widget.render('name', 'value')
|
||||
assert 'data-minimum-input-length="1"' in output
|
||||
assert 'data-minimum-input-length="2"' in output
|
||||
assert 'data-tags="true"' in output
|
||||
assert 'data-token-separators' in output
|
||||
|
||||
|
|
|
|||
|
|
@ -149,11 +149,19 @@ class HeavySelect2WidgetForm(forms.Form):
|
|||
class HeavySelect2MultipleWidgetForm(forms.Form):
|
||||
title = forms.CharField(max_length=50)
|
||||
genres = forms.MultipleChoiceField(
|
||||
widget=HeavySelect2MultipleWidget(data_view='heavy_data_1', choices=NUMBER_CHOICES),
|
||||
widget=HeavySelect2MultipleWidget(
|
||||
data_view='heavy_data_1',
|
||||
choices=NUMBER_CHOICES,
|
||||
attrs={'data-minimum-input-length': 0},
|
||||
),
|
||||
choices=NUMBER_CHOICES
|
||||
)
|
||||
featured_artists = forms.MultipleChoiceField(
|
||||
widget=HeavySelect2MultipleWidget(data_view='heavy_data_2', choices=NUMBER_CHOICES),
|
||||
widget=HeavySelect2MultipleWidget(
|
||||
data_view='heavy_data_2',
|
||||
choices=NUMBER_CHOICES,
|
||||
attrs={'data-minimum-input-length': 0},
|
||||
),
|
||||
choices=NUMBER_CHOICES,
|
||||
required=False
|
||||
)
|
||||
|
|
@ -182,6 +190,7 @@ class AddressChainedSelect2WidgetForm(forms.Form):
|
|||
search_fields=['name__icontains'],
|
||||
max_results=500,
|
||||
dependent_fields={'city': 'cities'},
|
||||
attrs={'data-minimum-input-length': 0},
|
||||
)
|
||||
)
|
||||
|
||||
|
|
@ -193,6 +202,7 @@ class AddressChainedSelect2WidgetForm(forms.Form):
|
|||
search_fields=['name__icontains'],
|
||||
dependent_fields={'country': 'country'},
|
||||
max_results=500,
|
||||
attrs={'data-minimum-input-length': 0},
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue