X-Git-Url: http://git.ithinksw.org/philo.git/blobdiff_plain/7ef5d942e4e1f7de42a389c196de3a13b31e8d45..9378da0590e3fcb8817d0c0309413bf59083ae8b:/models/fields/__init__.py diff --git a/models/fields/__init__.py b/models/fields/__init__.py index d8ed839..1f9603e 100644 --- a/models/fields/__init__.py +++ b/models/fields/__init__.py @@ -1,6 +1,10 @@ from django import forms +from django.core.exceptions import ValidationError +from django.core.validators import validate_slug from django.db import models from django.utils import simplejson as json +from django.utils.text import capfirst +from django.utils.translation import ugettext_lazy as _ from philo.forms.fields import JSONFormField from philo.validators import TemplateValidator, json_validator #from philo.models.fields.entities import * @@ -47,18 +51,85 @@ class JSONField(models.TextField): models.signals.pre_init.connect(self.fix_init_kwarg, sender=cls) def fix_init_kwarg(self, sender, args, kwargs, **signal_kwargs): + # Anything passed in as self.name is assumed to come from a serializer and + # will be treated as a json string. if self.name in kwargs: - kwargs[self.attname] = json.dumps(kwargs.pop(self.name)) + value = kwargs.pop(self.name) + + # Hack to handle the xml serializer's handling of "null" + if value is None: + value = 'null' + + kwargs[self.attname] = value def formfield(self, *args, **kwargs): kwargs["form_class"] = JSONFormField return super(JSONField, self).formfield(*args, **kwargs) +class SlugMultipleChoiceField(models.Field): + __metaclass__ = models.SubfieldBase + description = _("Comma-separated slug field") + + def get_internal_type(self): + return "TextField" + + def to_python(self, value): + if not value: + return [] + + if isinstance(value, list): + return value + + return value.split(',') + + def get_prep_value(self, value): + return ','.join(value) + + def formfield(self, **kwargs): + # This is necessary because django hard-codes TypedChoiceField for things with choices. + defaults = { + 'widget': forms.CheckboxSelectMultiple, + 'choices': self.get_choices(include_blank=False), + 'label': capfirst(self.verbose_name), + 'required': not self.blank, + '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() + + for k in kwargs.keys(): + 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) + form_class = forms.TypedMultipleChoiceField + return form_class(**defaults) + + def validate(self, value, model_instance): + invalid_values = [] + for val in value: + try: + validate_slug(val) + except ValidationError: + invalid_values.append(val) + + if invalid_values: + # should really make a custom message. + raise ValidationError(self.error_messages['invalid_choice'] % invalid_values) + + try: from south.modelsinspector import add_introspection_rules except ImportError: pass else: + add_introspection_rules([], ["^philo\.models\.fields\.SlugMultipleChoiceField"]) add_introspection_rules([], ["^philo\.models\.fields\.TemplateField"]) add_introspection_rules([], ["^philo\.models\.fields\.JSONField"]) \ No newline at end of file