1 from django import forms
2 from django.core.exceptions import ValidationError
3 from django.core.validators import validate_slug
4 from django.db import models
5 from django.utils import simplejson as json
6 from django.utils.text import capfirst
7 from django.utils.translation import ugettext_lazy as _
8 from philo.forms.fields import JSONFormField
9 from philo.validators import TemplateValidator, json_validator
10 #from philo.models.fields.entities import *
13 class TemplateField(models.TextField):
14 def __init__(self, allow=None, disallow=None, secure=True, *args, **kwargs):
15 super(TemplateField, self).__init__(*args, **kwargs)
16 self.validators.append(TemplateValidator(allow, disallow, secure))
19 class JSONDescriptor(object):
20 def __init__(self, field):
23 def __get__(self, instance, owner):
25 raise AttributeError # ?
27 if self.field.name not in instance.__dict__:
28 json_string = getattr(instance, self.field.attname)
29 instance.__dict__[self.field.name] = json.loads(json_string)
31 return instance.__dict__[self.field.name]
33 def __set__(self, instance, value):
34 instance.__dict__[self.field.name] = value
35 setattr(instance, self.field.attname, json.dumps(value))
37 def __delete__(self, instance):
38 del(instance.__dict__[self.field.name])
39 setattr(instance, self.field.attname, json.dumps(None))
42 class JSONField(models.TextField):
43 default_validators = [json_validator]
45 def get_attname(self):
46 return "%s_json" % self.name
48 def contribute_to_class(self, cls, name):
49 super(JSONField, self).contribute_to_class(cls, name)
50 setattr(cls, name, JSONDescriptor(self))
51 models.signals.pre_init.connect(self.fix_init_kwarg, sender=cls)
53 def fix_init_kwarg(self, sender, args, kwargs, **signal_kwargs):
54 if self.name in kwargs:
55 kwargs[self.attname] = json.dumps(kwargs.pop(self.name))
57 def formfield(self, *args, **kwargs):
58 kwargs["form_class"] = JSONFormField
59 return super(JSONField, self).formfield(*args, **kwargs)
62 class SlugMultipleChoiceField(models.Field):
63 __metaclass__ = models.SubfieldBase
64 description = _("Comma-separated slug field")
66 def get_internal_type(self):
69 def to_python(self, value):
73 if isinstance(value, list):
76 return value.split(',')
78 def get_prep_value(self, value):
79 return ','.join(value)
81 def formfield(self, **kwargs):
82 # This is necessary because django hard-codes TypedChoiceField for things with choices.
84 'widget': forms.CheckboxSelectMultiple,
85 'choices': self.get_choices(include_blank=False),
86 'label': capfirst(self.verbose_name),
87 'required': not self.blank,
88 'help_text': self.help_text
90 if self.has_default():
91 if callable(self.default):
92 defaults['initial'] = self.default
93 defaults['show_hidden_initial'] = True
95 defaults['initial'] = self.get_default()
97 for k in kwargs.keys():
98 if k not in ('coerce', 'empty_value', 'choices', 'required',
99 'widget', 'label', 'initial', 'help_text',
100 'error_messages', 'show_hidden_initial'):
103 defaults.update(kwargs)
104 form_class = forms.TypedMultipleChoiceField
105 return form_class(**defaults)
107 def validate(self, value, model_instance):
112 except ValidationError:
113 invalid_values.append(val)
116 # should really make a custom message.
117 raise ValidationError(self.error_messages['invalid_choice'] % invalid_values)
121 from south.modelsinspector import add_introspection_rules
125 add_introspection_rules([], ["^philo\.models\.fields\.SlugMultipleChoiceField"])
126 add_introspection_rules([], ["^philo\.models\.fields\.TemplateField"])
127 add_introspection_rules([], ["^philo\.models\.fields\.JSONField"])