django-orchestra/orchestra/models/fields.py

94 lines
3.2 KiB
Python

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