8000 Fix #544 -- Ensure correct attribute defaults (#547) · codingjoe/django-select2@c15de46 · GitHub
[go: up one dir, main page]

Skip to content

Commit c15de46

Browse files
mfrascacodingjoe
authored andcommitted
Fix applegrew#544 -- Ensure correct attribute defaults (applegrew#547)
dict.setdefault() does not change the default value if called twice. Therefore, defaults need to passed to the super call instead.
1 parent 898b2e8 commit c15de46

File tree

4 files changed

+83
-26
lines changed
  • testapp
  • 4 files changed

    +83
    -26
    lines changed

    django_select2/forms.py

    Lines changed: 31 additions & 19 deletions
    Original file line numberDiff line numberDiff line change
    @@ -70,16 +70,18 @@ class Select2Mixin:
    7070
    form media.
    7171
    """
    7272

    73-
    def build_attrs(self, *args, **kwargs):
    73+
    def build_attrs(self, base_attrs, extra_attrs=None):
    7474
    """Add select2 data attributes."""
    75-
    attrs = super(Select2Mixin, self).build_attrs(*args, **kwargs)
    75+
    default_attrs = {'data-minimum-input-length': 0}
    7676
    if self.is_required:
    77-
    attrs.setdefault('data-allow-clear', 'false')
    77+
    default_attrs['data-allow-clear'] = 'false'
    7878
    else:
    79-
    attrs.setdefault('data-allow-clear', 'true')
    80-
    attrs.setdefault('data-placeholder', '')
    79+
    default_attrs['data-allow-clear'] = 'true'
    80+
    default_attrs['data-placeholder'] = ''
    81+
    82+
    default_attrs.update(base_attrs)
    83+
    attrs = super().build_attrs(default_attrs, extra_attrs=extra_attrs)
    8184

    82-
    attrs.setdefault('data-minimum-input-length', 0)
    8385
    if 'class' in attrs:
    8486
    attrs['class'] += ' django-select2'
    8587
    else:
    @@ -120,12 +122,15 @@ def _get_media(self):
    120122
    class Select2TagMixin:
    121123
    """Mixin to add select2 tag functionality."""
    122124

    123-
    def build_attrs(self, *args, **kwargs):
    125+
    def build_attrs(self, base_attrs, extra_attrs=None):
    124126
    """Add select2's tag attributes."""
    125-
    self.attrs.setdefault('data-minimum-input-length', 1)
    126-
    self.attrs.setdefault('data-tags', 'true')
    127-
    self.attrs.setdefault('data-token-separators', '[",", " "]')
    128-
    return super(Select2TagMixin, self).build_attrs(*args, **kwargs)
    127+
    default_attrs = {
    128+
    'data-minimum-input-length': 1,
    129+
    'data-tags': 'true',
    130+
    'data-token-separators': '[",", " "]'
    131+
    }
    132+
    default_attrs.update(base_attrs)
    133+
    return super().build_attrs(default_attrs, extra_attrs=extra_attrs)
    129134

    130135

    131136
    class Select2Widget(Select2Mixin, forms.Select):
    @@ -226,20 +231,27 @@ def get_url(self):
    226231
    return self.data_url
    227232
    return reverse(self.data_view)
    228233

    229-
    def build_attrs(self, *args, **kwargs):
    234 8000 +
    def build_attrs(self, base_attrs, extra_attrs=None):
    230235
    """Set select2's AJAX attributes."""
    231-
    attrs = super(HeavySelect2Mixin, self).build_attrs(*args, **kwargs)
    236+
    237+
    default_attrs = {
    238+
    'data-ajax--url': self.get_url(),
    239+
    'data-ajax--cache': "true",
    240+
    'data-ajax--type': "GET",
    241+
    'data-minimum-input-length': 2,
    242+
    }
    243+
    244+
    if self.dependent_fields:
    245+
    default_attrs['data-select2-dependent-fields'] = " ".join(self.dependent_fields)
    246+
    247+
    default_attrs.update(base_attrs)
    248+
    249+
    attrs = super().build_attrs(default_attrs, extra_attrs=extra_attrs)
    232250

    233251
    # encrypt instance Id
    234252
    self.widget_id = signing.dumps(id(self))
    235253

    236254
    attrs['data-field_id'] = self.widget_id
    237-
    attrs.setdefault('data-ajax--url', self.get_url())
    238-
    attrs.setdefault('data-ajax--cache', "true")
    239-
    attrs.setdefault('data-ajax--type', "GET")
    240-
    attrs.setdefault('data-minimum-input-length', 2)
    241-
    if self.dependent_fields:
    242-
    attrs.setdefault('data-select2-dependent-fields', " ".join(self.dependent_fields))
    243255

    244256
    attrs['class'] += ' django-select2-heavy'
    245257
    return attrs

    tests/conftest.py

    Lines changed: 2 additions & 3 deletions
    Original file line numberDiff line numberDiff line change
    @@ -2,7 +2,6 @@
    22
    import string
    33

    44
    import pytest
    5-
    from django.utils.encoding import force_text
    65
    from selenium import webdriver
    76
    from selenium.common.exceptions import WebDriverException
    87

    @@ -22,11 +21,11 @@ def random_name(n):
    2221
    @pytest.yield_fixture(scope='session')
    2322
    def driver():
    2423
    chrome_options = webdriver.ChromeOptions()
    25-
    chrome_options.headless = True
    24+
    chrome_options.headless = False
    2625
    try:
    2726
    b = webdriver.Chrome(options=chrome_options)
    2827
    except WebDriverException as e:
    29-
    pytest.skip(force_text(e))
    28+
    pytest.skip(str(e))
    3029
    else:
    3130
    yield b
    3231
    b.quit()

    tests/test_forms.py

    Lines changed: 38 additions & 2 deletions
    Original file line numberDiff line numberDiff line change
    @@ -217,12 +217,17 @@ def test_multiple_widgets(self, db, live_server, driver):
    217217
    driver.find_element_by_css_selector('.select2-results')
    218218

    219219
    elem1, elem2 = driver.find_elements_by_css_selector('.select2-selection')
    220-
    elem1.click()
    221220

    221+
    elem1.click()
    222+
    search1 = driver.find_element_by_css_selector('.select2-search__field')
    223+
    search1.send_keys('fo')
    222224
    result1 = WebDriverWait(driver, 60).until(
    223225
    expected_conditions.presence_of_element_located((By.CSS_SELECTOR, '.select2-results li:first-child'))
    224226
    ).text
    227+
    225228
    elem2.click()
    229+
    search2 = driver.find_element_by_css_selector('.select2-search__field')
    230+
    search2.send_keys('fo')
    226231
    result2 = WebDriverWait(driver, 60).until(
    227232
    expected_conditions.presence_of_element_located((By.CSS_SELECTOR, '.select2-results li:first-child'))
    228233
    ).text
    @@ -315,6 +320,37 @@ def test_get_queryset(self):
    315320
    widget.queryset = Genre.objects.all()
    316321
    assert isinstance(widget.get_queryset(), QuerySet)
    317322

    323+
    def test_tag_attrs_Select2Widget(self):
    324+
    widget = Select2Widget()
    325+
    output = widget.render('name', 'value')
    326+
    assert 'data-minimum-input-length="0"' in output
    327+
    328+
    def test_custom_tag_attrs_Select2Widget(self):
    329+
    widget = Select2Widget(attrs={'data-minimum-input-length': '3'})
    330+
    output = widget.render('name', 'value')
    331+
    assert 'data-minimum-input-length="3"' in output
    332+
    333+
    def test_tag_attrs_ModelSelect2Widget(self):
    334+
    widget = ModelSelect2Widget(queryset=Genre.objects.all(), search_fields=['title__icontains'])
    335+
    output = widget.render('name', 'value')
    336+
    assert 'data-minimum-input-length="2"' in output
    337+
    338+
    def test_tag_attrs_ModelSelect2TagWidget(self):
    339+
    widget = ModelSelect2TagWidget(queryset=Genre.objects.all(), search_fields=['title__icontains'])
    340+
    output = widget.render('name', 'value')
    341+
    assert 'data-minimum-input-length="2"' in output
    342+
    343+
    def test_tag_attrs_HeavySelect2Widget(self):
    344+
    widget = HeavySelect2Widget(data_url='/foo/bar/')
    345+
    output = widget.render('name', 'value')
    346+
    assert 'data-minimum-input-length="2"' in output
    347+
    348+
    def test_custom_tag_attrs_ModelSelect2Widget(self):
    349+
    widget = ModelSelect2Widget(
    350+
    queryset=Genre.objects.all(), search_fields=['title__icontains'], attrs={'data-minimum-input-length': '3'})
    351+
    output = widget.render('name', 'value')
    352+
    assert 'data-minimum-input-length="3"' in output
    353+
    318354
    def test_get_search_fields(self):
    319355
    widget = ModelSelect2Widget()
    320356
    with pytest.raises(NotImplementedError):
    @@ -382,7 +418,7 @@ class TestHeavySelect2TagWidget(TestHeavySelect2Mixin):
    382418
    def test_tag_attrs(self):
    383419
    widget = ModelSelect2TagWidget(queryset=Genre.objects.all(), search_fields=['title__icontains'])
    384420
    output = widget.render('name', 'value')
    385-
    assert 'data-minimum-input-length="1"' in output
    421+
    assert 'data-minimum-input-length="2"' in output
    386422
    assert 'data-tags="true"' in output
    387423
    assert 'data-token-separators' in output
    388424

    tests/testapp/forms.py

    Lines changed: 12 additions & 2 deletions
    Original file line numberDiff line numberDiff line change
    @@ -149,11 +149,19 @@ class HeavySelect2WidgetForm(forms.Form):
    149149
    class HeavySelect2MultipleWidgetForm(forms.Form):
    150150
    title = forms.CharField(max_length=50)
    151151
    genres = forms.MultipleChoiceField(
    152-
    widget=HeavySelect2MultipleWidget(data_view='heavy_data_1', choices=NUMBER_CHOICES),
    152+
    widget=HeavySelect2MultipleWidget(
    153+
    data_view='heavy_data_1',
    154+
    choices=NUMBER_CHOICES,
    155+
    attrs={'data-minimum-input-length': 0},
    156+
    ),
    153157
    choices=NUMBER_CHOICES
    154158
    )
    155159
    featured_artists = forms.MultipleChoiceField(
    156-
    widget=HeavySelect2MultipleWidget(data_view='heavy_data_2', choices=NUMBER_CHOICES),
    160+
    widget=HeavySelect2MultipleWidget(
    161+
    data_view='heavy_data_2',
    162+
    choices=NUMBER_CHOICES,
    163+
    attrs={'data-minimum-input-length': 0},
    164+
    ),
    157165
    choices=NUMBER_CHOICES,
    158166
    required=False
    159167
    )
    @@ -182,6 +190,7 @@ class AddressChainedSelect2WidgetForm(forms.Form):
    182190
    search_fields=['name__icontains'],
    183191
    max_results=500,
    184192
    dependent_fields={'city': 'cities'},
    193+
    attrs={'data-minimum-input-length': 0},
    185194
    )
    186195
    )
    187196

    @@ -193,6 +202,7 @@ class AddressChainedSelect2WidgetForm(forms.Form):
    193202
    search_fields=['name__icontains'],
    194203
    dependent_fields={'country': 'country'},
    195204
    max_results=500,
    205+
    attrs={'data-minimum-input-length': 0},
    196206
    )
    197207
    )
    198208

    0 commit comments

    Comments
     (0)
    0