Login

CharField powered Tags with ChoiceField widget.

Author:
Husio
Posted:
August 22, 2009
Language:
Python
Version:
1.1
Tags:
tag forms field selectmultiple checbox
Score:
0 (after 0 ratings)

Shell example:

>>> pprint.pprint(settings.FORUM_TAGS)
((u'x11', 'Xorg'),
 (u'pacman', 'Pacman'),
 (u'aur', 'AUR'),
 (u'abs', 'ABS'),
 (u'howto', 'HOWTO'),
 (u'instalacja', 'Instalacja'),
 (u'offtopic', 'Offtopic'))
>>> t = Thread.objects.all()[0]
>>> pprint.pprint(t.tags)
[{'slug': u'pacman', 'title': 'Pacman'},
 {'slug': u'abs', 'title': 'ABS'},
 {'slug': u'howto', 'title': 'HOWTO'},
 {'slug': u'instalacja', 'title': 'Instalacja'},
 {'slug': u'offtopic', 'title': 'Offtopic'}]
>>> t.tags = [{'slug': 'abs'}, {'slug': 'howto'}
>>> t.save()
>>> t = Thread.objects.get(pk=t.pk)
>>> pprint.pprint(t.tags)
[{'slug': u'abs', 'title': 'ABS'}, {'slug': u'howto', 'title': 'HOWTO'}]
>>> t.tags = ['Offtopic', 'HOWTO']
>>> t.save()
>>> t = Thread.objects.get(pk=t.pk)
>>> pprint.pprint(t.tags)
[{'slug': u'howto', 'title': 'HOWTO'},
 {'slug': u'offtopic', 'title': 'Offtopic'}]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
from django import forms
from django.db import models
from django.utils.text import capfirst


"""
CharField based Tag field.
"""



class TagField(models.CharField):

    __metaclass__ = models.SubfieldBase

    def __init__(self, choices, separator=None, *args, **kwds):
        self.separator = separator or '\t'
        kwds['choices'] = choices
        kwds['max_length'] = sum((len(c[0]) for c in choices)) + len(choices)
        super(TagField, self).__init__(*args, **kwds)

    def to_python(self, value):
        if isinstance(value, unicode):
            tags = value.split(self.separator)
            return [{'title':c[1], 'slug': c[0]} for c in self.choices if c[0] in tags]
        return value

    def get_db_prep_save(self, value):
        data = []
        slug_list = []
        title_list = []
        try:
            slug_list = [v['slug'] for v in value]
        except TypeError:
            title_list = value
        for slug, title in self.choices:
            if slug_list and slug in slug_list \
                    or title in title_list:
                data.append(slug)
                continue
        return self.separator.join(data)

    def formfield(self, form_class=None, **kwargs):
        defaults = {
                'required': not self.blank,
                'label': capfirst(self.verbose_name),
                'help_text': self.help_text
            }
        form_class = form_class or TagFormField
        defaults['choices'] = self.get_choices(include_blank=False)
        defaults['coerce'] = self.to_python
        for k in kwargs.keys():
            if k not in ('choices', 'label', 'help_text', 'error_messages'):
                del kwargs[k]
        defaults.update(kwargs)
        return form_class(**defaults)


class TagCheckboxSelect(forms.widgets.CheckboxSelectMultiple):
    def __init__(self, *args, **kwds):
        super(TagCheckboxSelect, self).__init__(*args, **kwds)

    def render(self, name, value, attrs=None, choices=()):
        data = []
        if value:
            data = [v['slug'] for v in value]
        return super(TagCheckboxSelect, self).render(name, data, attrs, choices)


class TagFormField(forms.ChoiceField):

    widget = TagCheckboxSelect
    field = TagField

    def __init__(self, *args, **kwds):
        kwds.pop('coerce', None)
        super(TagFormField, self).__init__(*args, **kwds)

    def clean(self, value):
        if not value:
            raise forms.ValidationError('Choose at least one tag')
        data = []
        for choice in self.choices:
            if choice[0] in value:
                data.append(choice[1])
                continue
        return data

More like this

Comments

Please login first before commenting.