django-selectable / selectable / forms / fields.py

from django import forms
from django.core.exceptions import ValidationError
from django.core.validators import EMPTY_VALUES
from django.utils.translation import ugettext as _

from selectable.forms.widgets import AutoCompleteSelectWidget, AutoComboboxSelectWidget
from selectable.forms.widgets import AutoCompleteSelectMultipleWidget, AutoComboboxSelectMultipleWidget

__all__ = (
    'AutoCompleteSelectField',
    'AutoComboboxSelectField',
    'AutoCompleteSelectMultipleField',
    'AutoComboboxSelectMultipleField',
)


class AutoCompleteSelectField(forms.Field):
    widget = AutoCompleteSelectWidget

    default_error_messages = {
        'invalid_choice': _(u'Select a valid choice. That choice is not one of the available choices.'),
    }

    def __init__(self, lookup_class, *args, **kwargs):
        self.lookup_class = lookup_class
        self.allow_new = kwargs.pop('allow_new', False)
        kwargs['widget'] = self.widget(lookup_class, allow_new=self.allow_new)
        super(AutoCompleteSelectField, self).__init__(*args, **kwargs)


    def to_python(self, value):
        if value in EMPTY_VALUES:
            return None
        if isinstance(value, list):
            # Input comes from an AutoComplete widget. It's two
            # components: text and id
            if len(value) != 2:
                raise ValidationError(self.error_messages['invalid_choice'])
            lookup =self.lookup_class()
            if value[1] in EMPTY_VALUES:
                if not self.allow_new:
                    if value[0]:
                        raise ValidationError(self.error_messages['invalid_choice'])
                    else:
                        return None
                value = lookup.create_item(value[0])  
            else:
                value = lookup.get_item(value[1])
                if value is None:
                    raise ValidationError(self.error_messages['invalid_choice'])
        return value


class AutoComboboxSelectField(AutoCompleteSelectField):
    widget = AutoComboboxSelectWidget


class AutoCompleteSelectMultipleField(forms.Field):
    widget = AutoCompleteSelectMultipleWidget

    default_error_messages = {
        'invalid_choice': _(u'Select a valid choice. That choice is not one of the available choices.'),
    }

    def __init__(self, lookup_class, *args, **kwargs):
        self.lookup_class = lookup_class
        kwargs['widget'] = self.widget(lookup_class)
        super(AutoCompleteSelectMultipleField, self).__init__(*args, **kwargs)


    def to_python(self, value):
        if value in EMPTY_VALUES:
            return None
        if isinstance(value, list):
            # Input comes from an AutoComplete widget. It's two
            # components: text and id
            if len(value) != 2:
                raise ValidationError(self.error_messages['invalid_choice'])
            lookup =self.lookup_class()
            if value[1] in EMPTY_VALUES:
                return None
            else:
                ids = value[1]
                if not isinstance(ids, list):
                    ids = [ids]
                value = []
                for v in ids:
                    item = lookup.get_item(v)
                    if item is None:
                        raise ValidationError(self.error_messages['invalid_choice'])
                    value.append(item)
        return value


class AutoComboboxSelectMultipleField(AutoCompleteSelectMultipleField):
    widget = AutoComboboxSelectMultipleWidget
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.