import os from django.core import exceptions from django.core.urlresolvers import reverse from django.db import models from django.db.models.fields.files import FileField, FieldFile from django.utils.text import capfirst from ..forms.fields import MultiSelectFormField from ..utils.apps import isinstalled class MultiSelectField(models.CharField, metaclass=models.SubfieldBase): def formfield(self, **kwargs): 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, connection=None, prepared=False): if isinstance(value, str): return value else: return ','.join(value) def to_python(self, value): if value: if isinstance(value, str): return value.split(',') return value return [] def contribute_to_class(self, cls, name): super(MultiSelectField, self).contribute_to_class(cls, name) if self.choices: def func(self, field=name, choices=dict(self.choices)): return ','.join([choices.get(value, value) for value in getattr(self, field)]) setattr(cls, 'get_%s_display' % self.name, func) def validate(self, value, model_instance): if self.choices: arr_choices = self.get_choices_selected(self.get_choices_default()) for opt_select in value: if (opt_select not in arr_choices): msg = self.error_messages['invalid_choice'] % {'value': opt_select} raise exceptions.ValidationError(msg) def get_choices_selected(self, arr_choices=''): if not arr_choices: return False return [value for value, __ in arr_choices] class NullableCharField(models.CharField): def get_db_prep_value(self, value, connection=None, prepared=False): return value or None class PrivateFieldFile(FieldFile): @property def url(self): self._require_file() app_label = self.instance._meta.app_label model_name = self.instance._meta.object_name.lower() field_name = self.field.name pk = self.instance.pk filename = os.path.basename(self.path) args = [app_label, model_name, field_name, pk, filename] return reverse('private-media', args=args) @property def condition(self): return self.field.condition @property def attachment(self): return self.field.attachment class PrivateFileField(FileField): attr_class = PrivateFieldFile def __init__(self, verbose_name=None, name=None, upload_to='', storage=None, attachment=True, condition=lambda request, instance: request.user.is_superuser, **kwargs): super(PrivateFileField, self).__init__(verbose_name, name, upload_to, storage, **kwargs) self.condition = condition self.attachment = attachment