diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 9f37701..f09d291 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -5,7 +5,7 @@ Changelog for django-agnocomplete
master (unreleased)
===================
-Nothing here yet.
+* Fix bug in AgnocompleteWidgetMixin when template-based widgets are used (Django>=1.11).
0.11.0 (2018-01-25)
===================
diff --git a/agnocomplete/widgets.py b/agnocomplete/widgets.py
index 3061bb8..f4ef21c 100644
--- a/agnocomplete/widgets.py
+++ b/agnocomplete/widgets.py
@@ -45,20 +45,6 @@ def _agnocomplete_build_attrs(self, attrs):
return attrs
- def render_options(self, *args):
- # Django >= 1.10, only "selected_choices" in the arg list
- if len(args) == 1:
- selected_choices = args[0]
- else:
- # Django < 1.10 - selected_choices is the second arg.
- _, selected_choices = args
- selected_choices = set(text(v) for v in selected_choices)
- selected_choices_tuples = self.agnocomplete.selected(selected_choices)
- output = []
- for option_value, option_label in selected_choices_tuples:
- output.append(self.render_option(selected_choices, option_value, option_label)) # noqa
- return '\n'.join(output)
-
if StrictVersion(get_version()) < StrictVersion('1.11'):
class AgnocompleteWidgetMixin(_AgnocompleteWidgetMixin):
@@ -69,6 +55,20 @@ def build_attrs(self, extra_attrs=None, **kwargs):
attrs = super(AgnocompleteWidgetMixin, self).build_attrs(
extra_attrs, **kwargs)
return self._agnocomplete_build_attrs(attrs)
+
+ def render_options(self, *args):
+ # Django >= 1.10, only "selected_choices" in the arg list
+ if len(args) == 1:
+ selected_choices = args[0]
+ else:
+ # Django < 1.10 - selected_choices is the second arg.
+ _, selected_choices = args
+ selected_choices = set(text(v) for v in selected_choices)
+ selected_choices_tuples = self.agnocomplete.selected(selected_choices)
+ output = []
+ for option_value, option_label in selected_choices_tuples:
+ output.append(self.render_option(selected_choices, option_value, option_label)) # noqa
+ return '\n'.join(output)
else:
class AgnocompleteWidgetMixin(_AgnocompleteWidgetMixin):
"""
@@ -79,6 +79,33 @@ def build_attrs(self, base_attrs, extra_attrs=None):
base_attrs, extra_attrs)
return self._agnocomplete_build_attrs(attrs)
+ """
+ Returns the selected option set in order to retrieve the behaviour of
+ AgnocompleteWidgetMixin.render_options()
+ """
+ def _agnocomplete_selected_options(self, options, value):
+ selected_options = {}
+
+ for opt in options:
+ opt_value = text(opt.get('value'))
+ opt_selected = (opt_value in value)
+
+ opt['selected'] = opt_selected
+ opt['attrs']['selected'] = opt_selected
+
+ if opt_selected:
+ selected_options[opt_value] = opt
+
+ return list(selected_options.values())
+
+ """
+ Render only selected options
+ """
+ def optgroups(self, name, value, attrs=None):
+ _selected_options = self._agnocomplete_selected_options
+ for name, options, index in super(AgnocompleteWidgetMixin, self).optgroups(name, value, attrs):
+ yield (name, _selected_options(options, value), index)
+
class AgnocompleteSelect(AgnocompleteWidgetMixin, widgets.Select):
"""
diff --git a/demo/tests/test_fields.py b/demo/tests/test_fields.py
index 3e42b96..893db7c 100644
--- a/demo/tests/test_fields.py
+++ b/demo/tests/test_fields.py
@@ -1,22 +1,34 @@
-from django.test import TestCase
-from django.core.urlresolvers import reverse
+from distutils.version import StrictVersion
+from django import forms, get_version
+from django.core.urlresolvers import reverse
+from django.test import TestCase
import six
+from agnocomplete import fields
+from agnocomplete.exceptions import UnregisteredAgnocompleteException
from agnocomplete.fields import (
AgnocompleteField,
AgnocompleteMultipleField,
AgnocompleteModelMultipleField,
)
-from agnocomplete.exceptions import UnregisteredAgnocompleteException
-
+from agnocomplete.forms import UserContextFormMixin
from demo.autocomplete import (
AutocompleteColor,
HiddenAutocompleteURL,
HiddenAutocompleteURLReverse,
AutocompleteTag,
+ AutocompletePersonDomain,
)
-from demo.models import Tag
+from demo.models import Tag, Person
+from demo.tests import LoaddataTestCase
+
+
+def is_selected_attr():
+ if StrictVersion(get_version()) < StrictVersion('1.11'):
+ return 'selected="selected"'
+ else:
+ return 'selected'
class AgnocompleteInstanceTest(TestCase):
@@ -70,8 +82,57 @@ def test_class_url_reversed(self):
)
-class MultipleSelectTest(TestCase):
+class ModelSelectTest(LoaddataTestCase):
+ class _Form(UserContextFormMixin, forms.Form):
+ person = fields.AgnocompleteModelField(AutocompletePersonDomain,
+ to_field_name='email')
+
+ def setUp(self):
+ super(ModelSelectTest, self).setUp()
+ self.alice = Person.objects.get(pk=1)
+ self.bob = Person.objects.get(pk=3)
+
+ self.invalid_pk = Person.objects.order_by('pk').last().pk + 1
+
+ def test_render(self):
+ form = self._Form(
+ user=None,
+ data={'person': self.bob.email},
+ )
+
+ # bob is selected => only bob '.format(
+ self.aliceinchains.email, is_selected_attr(), self.aliceinchains
+ ),
+ html_form
+ )
+
+ def test_render_no_selection(self):
+ # none is selected => no