Created
March 5, 2012 16:08
-
-
Save coordt/1979040 to your computer and use it in GitHub Desktop.
Django MultiSelectField
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
A model field and widget that allows selecting multiple items from a static | |
list of choices. Based on http://djangosnippets.org/snippets/1200/ | |
""" | |
from django.db import models | |
from django.core import exceptions | |
from django import forms | |
from django.utils.text import capfirst | |
class MultiSelectFormField(forms.MultipleChoiceField): | |
widget = forms.CheckboxSelectMultiple | |
def __init__(self, *args, **kwargs): | |
self.max_choices = kwargs.pop('max_choices', 0) | |
super(MultiSelectFormField, self).__init__(*args, **kwargs) | |
def clean(self, value): | |
if not value and self.required: | |
raise forms.ValidationError(self.error_messages['required']) | |
if value and self.max_choices and len(value) > self.max_choices: | |
raise forms.ValidationError('You must select a maximum of %s choice%s.' | |
% (apnumber(self.max_choices), pluralize(self.max_choices))) | |
return value | |
def validate(self, value, model_instance): | |
arr_choices = self.get_choices_selected(self.get_choices_default()) | |
for opt_select in value: | |
if (opt_select not in arr_choices): | |
raise exceptions.ValidationError(self.error_messages['invalid_choice'] % value) | |
return | |
def get_choices_selected(self, arr_choices=''): | |
if not arr_choices: | |
return False | |
list = [] | |
for choice_selected in arr_choices: | |
list.append(choice_selected[0]) | |
return list | |
class MultiSelectField(models.Field): | |
__metaclass__ = models.SubfieldBase | |
def get_internal_type(self): | |
return "CharField" | |
def get_choices_default(self): | |
return self.get_choices(include_blank=False) | |
def _get_FIELD_display(self, field): | |
value = getattr(self, field.attname) | |
choicedict = dict(field.choices) | |
def value_to_string(self, obj): | |
value = self._get_val_from_obj(obj) | |
return self.get_db_prep_value(value) | |
def formfield(self, **kwargs): | |
# don't call super, as that overrides default widget if it has choices | |
defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), | |
'help_text': self.help_text, 'choices':self.choices} | |
if self.has_default(): | |
defaults['initial'] = self.get_default() | |
defaults.update(kwargs) | |
return MultiSelectFormField(**defaults) | |
def get_db_prep_value(self, value, *args, **kwargs): | |
if isinstance(value, basestring): | |
return value | |
elif isinstance(value, list): | |
return ",".join(value) | |
def to_python(self, value): | |
if isinstance(value, (list, tuple)): | |
return value | |
elif value is None: | |
return '' | |
return value.split(",") | |
def contribute_to_class(self, cls, name): | |
super(MultiSelectField, self).contribute_to_class(cls, name) | |
if self.choices: | |
func = lambda self, fieldname = name, choicedict = dict(self.choices):",".join([choicedict.get(value,value) for value in getattr(self,fieldname)]) | |
setattr(cls, 'get_%s_display' % self.name, func) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Not work on Django 1.3.1
"Value ['a', 'b', 'c'] is not a valid choice."
I am don't know how it is fix.