Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4defb8112b | ||
|
|
bb90be77b7 | ||
|
|
18647161a1 | ||
|
|
3e6c1fc3ba |
@@ -1,6 +1,12 @@
|
||||
Changelog Summary
|
||||
=================
|
||||
|
||||
### v5.4.2
|
||||
* Fixed initial data not being shown for heavy widgets.
|
||||
|
||||
### v5.4.1
|
||||
* Fixed memory leak in `ModelSelect2Mixin` and subclasses
|
||||
|
||||
### v5.4.0
|
||||
* Added `Select2TagWidget` a light widget with tagging support
|
||||
|
||||
|
||||
@@ -9,4 +9,4 @@ The app includes Select2 driven Django Widgets and Form Fields.
|
||||
|
||||
"""
|
||||
|
||||
__version__ = "5.4.0"
|
||||
__version__ = "5.4.2"
|
||||
|
||||
@@ -49,6 +49,7 @@ Light widgets are normally named, i.e. there is no
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
from functools import reduce
|
||||
from itertools import chain
|
||||
|
||||
from django import forms
|
||||
from django.core import signing
|
||||
@@ -233,6 +234,7 @@ class HeavySelect2Mixin(Select2Mixin):
|
||||
|
||||
def render_options(self, choices, selected_choices):
|
||||
"""Render only selected options."""
|
||||
choices = chain(choices, self.choices)
|
||||
output = ['<option></option>' if not self.is_required else '']
|
||||
choices = {(k, v) for k, v in choices if k in selected_choices}
|
||||
selected_choices = {force_text(v) for v in selected_choices}
|
||||
@@ -274,6 +276,8 @@ class HeavySelect2MultipleWidget(HeavySelect2Mixin, forms.SelectMultiple):
|
||||
|
||||
class HeavySelect2TagWidget(Select2TagMixin, HeavySelect2MultipleWidget):
|
||||
|
||||
"""Select2 tag widget."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
@@ -349,7 +353,7 @@ class ModelSelect2Mixin(object):
|
||||
:return: Filtered queryset
|
||||
:rtype: :class:`.django.db.models.QuerySet`
|
||||
"""
|
||||
if not queryset:
|
||||
if queryset is None:
|
||||
queryset = self.get_queryset()
|
||||
search_fields = self.get_search_fields()
|
||||
select = Q()
|
||||
@@ -398,6 +402,7 @@ class ModelSelect2Mixin(object):
|
||||
choices = {self.choices.choice(obj)
|
||||
for obj in self.choices.queryset.filter(pk__in=selected_choices)}
|
||||
else:
|
||||
choices = chain(choices, self.choices)
|
||||
choices = {(k, v) for k, v in choices if k in selected_choices}
|
||||
selected_choices = {force_text(v) for v in selected_choices}
|
||||
for option_value, option_label in choices:
|
||||
@@ -414,7 +419,7 @@ class ModelSelect2Widget(ModelSelect2Mixin, HeavySelect2Widget):
|
||||
|
||||
class MyWidget(ModelSelect2Widget):
|
||||
search_fields = [
|
||||
'title__icontians',
|
||||
'title__icontains',
|
||||
]
|
||||
|
||||
class MyModelForm(forms.ModelForm):
|
||||
@@ -458,7 +463,7 @@ class ModelSelect2MultipleWidget(ModelSelect2Mixin, HeavySelect2MultipleWidget):
|
||||
class ModelSelect2TagWidget(Select2TagMixin, ModelSelect2MultipleWidget):
|
||||
|
||||
"""
|
||||
Select2 model field with tag support.
|
||||
Select2 model widget with tag support.
|
||||
|
||||
This it not a simple drop in widget.
|
||||
It requires to implement you own :func:`.value_from_datadict`
|
||||
|
||||
+14
-1
@@ -30,6 +30,11 @@ class TestSelect2Mixin(object):
|
||||
form = forms.AlbumSelect2WidgetForm()
|
||||
widget_cls = Select2Widget
|
||||
|
||||
def test_initial_data(self, genres):
|
||||
genre = genres[0]
|
||||
form = self.form.__class__(initial={'primary_genre': genre.pk})
|
||||
assert text_type(genre) in form.as_p()
|
||||
|
||||
def test_initial_form_class(self):
|
||||
widget = self.widget_cls(attrs={'class': 'my-class'})
|
||||
assert 'my-class' in widget.render('name', None)
|
||||
@@ -81,9 +86,12 @@ class TestSelect2Mixin(object):
|
||||
|
||||
class TestHeavySelect2Mixin(TestSelect2Mixin):
|
||||
url = reverse('heavy_select2_widget')
|
||||
form = forms.HeavySelect2WidgetForm(initial={'primary_genre': [1]})
|
||||
form = forms.HeavySelect2WidgetForm(initial={'primary_genre': 1})
|
||||
widget_cls = HeavySelect2Widget
|
||||
|
||||
def test_initial_data(self):
|
||||
assert 'One' in self.form.as_p()
|
||||
|
||||
def test_initial_form_class(self):
|
||||
widget = self.widget_cls(data_view='heavy_data_1', attrs={'class': 'my-class'})
|
||||
assert 'my-class' in widget.render('name', None)
|
||||
@@ -129,6 +137,11 @@ class TestHeavySelect2Mixin(TestSelect2Mixin):
|
||||
class TestModelSelect2Mixin(TestHeavySelect2Mixin):
|
||||
form = forms.AlbumModelSelect2WidgetForm(initial={'primary_genre': 1})
|
||||
|
||||
def test_initial_data(self, genres):
|
||||
genre = genres[0]
|
||||
form = self.form.__class__(initial={'primary_genre': genre.pk})
|
||||
assert text_type(genre) in form.as_p()
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def genres(self, db):
|
||||
return mommy.make(Genre, 100)
|
||||
|
||||
@@ -114,11 +114,13 @@ class Select2WidgetForm(forms.Form):
|
||||
|
||||
class HeavySelect2WidgetForm(forms.Form):
|
||||
artist = forms.ChoiceField(
|
||||
widget=HeavySelect2Widget(data_view='heavy_data_1', choices=NUMBER_CHOICES)
|
||||
widget=HeavySelect2Widget(data_view='heavy_data_1'),
|
||||
choices=NUMBER_CHOICES
|
||||
)
|
||||
primary_genre = forms.ChoiceField(
|
||||
widget=HeavySelect2Widget(data_view='heavy_data_2', choices=NUMBER_CHOICES),
|
||||
required=False
|
||||
widget=HeavySelect2Widget(data_view='heavy_data_2'),
|
||||
required=False,
|
||||
choices=NUMBER_CHOICES
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user