Source code for dal.widgets
"""Autocomplete widgets bases."""
import copy
from django import VERSION
from django import forms
from django.core.urlresolvers import reverse
from django.utils import six
[docs]class WidgetMixin(object):
"""Base mixin for autocomplete widgets.
.. py:attribute:: url
Absolute URL to the autocomplete view for the widget. It can be set to
a a URL name, in which case it will be reversed when the attribute is
accessed.
.. py:attribute:: forward
List of field names to forward to the autocomplete view, useful to
filter results using values of other fields in the form.
"""
def __init__(self, url=None, forward=None, *args, **kwargs):
"""Instanciate a widget with a URL and a list of fields to forward."""
self.url = url
self.forward = forward or []
super(WidgetMixin, self).__init__(*args, **kwargs)
[docs] def build_attrs(self, *args, **kwargs):
"""Build HTML attributes for the widget."""
attrs = super(WidgetMixin, self).build_attrs(*args, **kwargs)
if self.url is not None:
attrs['data-autocomplete-light-url'] = self.url
autocomplete_function = getattr(self, 'autocomplete_function', None)
if autocomplete_function:
attrs.setdefault('data-autocomplete-light-function',
autocomplete_function)
if self.forward:
attrs.setdefault('data-autocomplete-light-forward',
','.join(self.forward))
return attrs
[docs] def filter_choices_to_render(self, selected_choices):
"""Replace self.choices with selected_choices."""
self.choices = [c for c in self.choices if
six.text_type(c[0]) in selected_choices]
[docs] def render_options(self, *args):
"""
Django-compatibility method for option rendering.
Should only render selected options, by setting self.choices before
calling the parent method.
"""
selected_choices_arg = 1 if VERSION < (1, 10) else 0
# Filter out None values, not needed for autocomplete
selected_choices = [c for c in args[selected_choices_arg] if c]
if self.url:
all_choices = copy.copy(self.choices)
self.filter_choices_to_render(selected_choices)
html = super(WidgetMixin, self).render_options(*args)
if self.url:
self.choices = all_choices
return html
def _get_url(self):
if self._url is None:
return None
if '/' in self._url:
return self._url
return reverse(self._url)
def _set_url(self, url):
self._url = url
url = property(_get_url, _set_url)
[docs]class Select(WidgetMixin, forms.Select):
"""Replacement for Django's Select to render only selected choices."""
[docs]class SelectMultiple(WidgetMixin, forms.SelectMultiple):
"""Replacement SelectMultiple to render only selected choices."""
[docs]class QuerySetSelectMixin(WidgetMixin):
"""QuerySet support for choices."""
[docs] def filter_choices_to_render(self, selected_choices):
"""Filter out un-selected choices if choices is a QuerySet."""
self.choices.queryset = self.choices.queryset.filter(
pk__in=[c for c in selected_choices if c]
)