Created
August 28, 2013 00:08
-
-
Save mattmcc/6360641 to your computer and use it in GitHub Desktop.
This file contains 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
class ChoiceList(list): | |
def __init__(self, *args, **kwargs): | |
self.choices = kwargs.pop('choices') | |
super(ChoiceList, self).__init__(*args, **kwargs) | |
def items(self): | |
return [(k, v) for k, v in self.choices if k in self] | |
class ChoiceArrayField(ArrayField): | |
def __init__(self, *args, **kwargs): | |
#self.choices = kwargs.pop('choices') | |
super(ChoiceArrayField, self).__init__(self, *args, **kwargs) | |
# Copied from Django 1.6, which fixes #18162, and adjusted to | |
# support array fields | |
def formfield(self, form_class=None, **kwargs): | |
""" | |
Returns a django.forms.Field instance for this database Field. | |
""" | |
defaults = {'required': not self.blank, | |
'label': capfirst(self.verbose_name), | |
'help_text': self.help_text} | |
if self.has_default(): | |
if callable(self.default): | |
defaults['initial'] = self.default | |
defaults['show_hidden_initial'] = True | |
else: | |
defaults['initial'] = self.get_default() | |
if self.choices: | |
defaults['choices'] = self.get_choices(include_blank=False) | |
defaults['coerce'] = lambda val: val | |
if form_class is None or not issubclass(form_class, forms.TypedMultipleChoiceField): | |
form_class = forms.TypedMultipleChoiceField | |
# Many of the subclass-specific formfield arguments (min_value, | |
# max_value) don't apply for choice fields, so be sure to only pass | |
# the values that TypedChoiceField will understand. | |
for k in list(kwargs): | |
if k not in ('coerce', 'empty_value', 'choices', 'required', | |
'widget', 'label', 'initial', 'help_text', | |
'error_messages', 'show_hidden_initial'): | |
del kwargs[k] | |
defaults.update(kwargs) | |
if form_class is None: | |
form_class = forms.CharField | |
return form_class(**defaults) | |
# Copied from django.db.models.fields.Field and adjusted to support | |
# multiple values. | |
def validate(self, value, model_instance): | |
""" | |
Validates value and throws ValidationError. Subclasses should override | |
this to provide validation logic. | |
""" | |
if not self.editable: | |
# Skip validation for non-editable fields. | |
return | |
if self._choices and value: | |
if isinstance(value, (list, tuple)): | |
value_set = set(value) | |
else: | |
value_set = set((value,)) | |
for option_key, option_value in self.choices: | |
if isinstance(option_value, (list, tuple)): | |
# This is an optgroup, so look inside the group for | |
# options. | |
optgroup_keys = [key for key, value in option_value] | |
for optgroup_key, optgroup_value in option_value: | |
if optgroup_key in value_set: | |
value_set.remove(optgroup) | |
elif option_key in value_set: | |
value_set.remove(option_key) | |
if value_set: | |
msg = self.error_messages['invalid_choice'] % value | |
raise exceptions.ValidationError(msg) | |
return | |
if value is None and not self.null: | |
raise exceptions.ValidationError(self.error_messages['null']) | |
if not self.blank and value in validators.EMPTY_VALUES: | |
raise exceptions.ValidationError(self.error_messages['blank']) | |
def to_python(self, value): | |
if value is None: | |
value = [] | |
return ChoiceList(value, choices=self.choices) | |
add_introspection_rules([ | |
( | |
[ChoiceArrayField], | |
[], | |
{'dbtype': ["_array_type", {"default" : "int"}]}, | |
), | |
], ['someapp\.fields\.ChoiceArrayField'] | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment