diff --git a/docs/ref/filters.txt b/docs/ref/filters.txt index 51cc3dfde..135ec91b0 100644 --- a/docs/ref/filters.txt +++ b/docs/ref/filters.txt @@ -86,7 +86,11 @@ argument. ``widget`` ~~~~~~~~~~ -The django.form Widget class which will represent the ``Filter``. +The django.form Widget class which will represent the ``Filter``. In addition +to the widgets that are included with Django that you can use there are +additional ones that django-filte provides which may be useful: + * ``filter.widgets.LinkWidget`` -- this displays the options in a mannner + similar to the way the Django Admin does, as a series of links. ``action`` ~~~~~~~~~~ diff --git a/filter/tests.py b/filter/tests.py index 5dfb0c1c2..08ef9590e 100644 --- a/filter/tests.py +++ b/filter/tests.py @@ -3,6 +3,7 @@ >>> from django.core.management import call_command >>> import filter >>> from filter import FilterSet +>>> from filter.widgets import LinkWidget >>> from filter.models import User, Comment, Book, STATUS_CHOICES >>> call_command('loaddata', 'test_data', verbosity=0) @@ -275,5 +276,27 @@ >>> f= F({'price_0': '15', 'price_1': 'lt'}) >>> f.qs [] +>>> class F(FilterSet): +... status = filter.ChoiceFilter(widget=LinkWidget, choices=STATUS_CHOICES) +... class Meta: +... model = User +... fields = ['status'] +>>> f = F() +>>> f.qs +[, , ] +>>> print f.form + +>>> f = F({'status': '1'}) +>>> f.qs +[] +>>> print f.form + + """} diff --git a/filter/widgets.py b/filter/widgets.py index 4df54aece..4a057a445 100644 --- a/filter/widgets.py +++ b/filter/widgets.py @@ -1,4 +1,52 @@ +from itertools import chain +from urllib import urlencode + from django import forms +from django.forms.widgets import flatatt +from django.utils.encoding import force_unicode +from django.utils.safestring import mark_safe + +class LinkWidget(forms.Widget): + def __init__(self, attrs=None, choices=()): + super(LinkWidget, self).__init__(attrs) + + self.choices = list(choices) + + def value_from_datadict(self, data, files, name): + value = super(LinkWidget, self).value_from_datadict(data, files, name) + self.data = data + return value + + def render(self, name, value, attrs=None, choices=()): + if value is None: + value = '' + final_attrs = self.build_attrs(attrs) + output = [u'' % flatatt(final_attrs)] + options = self.render_options(choices, [value], name) + if options: + output.append(options) + output.append('') + return mark_safe(u'\n'.join(output)) + + def render_options(self, choices, selected_choices, name): + def render_option(option_value, option_label): + option_value = force_unicode(option_value) + data = self.data.copy() + data[name] = option_value + try: + url = data.urlencode() + except AttributeError: + url = '?%s' % urlencode(data) + return '%s' % (url, option_label) + selected_choices = set(force_unicode(v) for v in selected_choices) + output = [] + for option_value, option_label in chain(self.choices, choices): + if isinstance(option_label, (list, tuple)): + for option in option_label: + output.append(render_option(*option)) + else: + output.append(render_option(option_value, option_label)) + return u'\n'.join(output) class RangeWidget(forms.MultiWidget): def __init__(self, attrs=None):