Source code for ls.joyous.fields

# ------------------------------------------------------------------------------
# Joyous Fields
# ------------------------------------------------------------------------------
import sys
from django.db.models import Field
from django.core.exceptions import ValidationError
from django.forms.fields import Field as FormField
from django.forms import TypedMultipleChoiceField, CheckboxSelectMultiple
from django.utils.encoding import force_str
from .utils.recurrence import Recurrence
from .widgets import RecurrenceWidget

# ------------------------------------------------------------------------------
[docs]class RecurrenceField(Field): """ DB Field for recurrences """ description = "The rule for recurring events" def __init__(self, *args, **kwargs): kwargs["max_length"] = 255 super().__init__(*args, **kwargs) def deconstruct(self): name, path, args, kwargs = super().deconstruct() del kwargs["max_length"] return name, path, args, kwargs def from_db_value(self, value, *args): return self.to_python(value) def to_python(self, value): if not value: return None if isinstance(value, Recurrence): return value try: return Recurrence(value) except (TypeError, ValueError, UnboundLocalError) as err: raise ValidationError("Invalid input for recurrence {}".format(err)) def value_to_string(self, obj): value = self.value_from_object(obj) return self.get_prep_value(value) def get_prep_value(self, rule): return repr(rule) def get_prep_lookup(self, lookup_type, value): """Sorry recurrences cannot be used in where clauses""" raise TypeError('Lookup type %r not supported.' % lookup_type) def formfield(self, **kwargs): defaults = {'form_class': RecurrenceFormField} defaults.update(kwargs) return super().formfield(**defaults) def get_internal_type(self): return "CharField"
# ------------------------------------------------------------------------------ class RecurrenceFormField(FormField): widget = RecurrenceWidget # ------------------------------------------------------------------------------
[docs]class MultipleSelectField(Field): """ Field with multiple *static* choices (not via m2m) From https://gist.github.com/kottenator/9a50e4207cff15c03f8e by Rostyslav Bryzgunov Value is stored in DB as comma-separated values Default widget is forms.CheckboxSelectMultiple Python value: list of values """ # See also https://github.com/goinnn/django-multiselectfield def __init__(self, *args, **kwargs): kwargs["max_length"] = 255 super().__init__(*args, **kwargs) def deconstruct(self): name, path, args, kwargs = super().deconstruct() del kwargs["max_length"] return name, path, args, kwargs def from_db_value(self, value, *args): return self.to_python(value) def to_python(self, value): if not value: return [] if isinstance(value, list): return value return value.split(",") def value_to_string(self, obj): value = self.value_from_object(obj) return self.get_prep_value(value) def get_prep_value(self, value): if not value: return "" return ",".join(value) def get_prep_lookup(self, lookup_type, value): """Sorry multiselects cannot be used in where clauses""" raise TypeError('Lookup type %r not supported.' % lookup_type) def _coerceChoice(self, choice): options = [option[0] for option in self.choices] if choice not in options: raise ValidationError(self.error_messages['invalid_choice'], code='invalid_choice', params={'value': choice}) return choice def formfield(self, **kwargs): defaults = {'choices_form_class': MultipleSelectFormField, 'choices': self.choices, 'coerce': self._coerceChoice} defaults.update(kwargs) return super().formfield(**defaults) def get_internal_type(self): return "CharField" def validate(self, value, model_instance): if not self.editable: return if value is None and not self.null: raise ValidationError(self.error_messages['null'], code='null') if not self.blank and value in self.empty_values: raise ValidationError(self.error_messages['blank'], code='blank') def contribute_to_class(self, cls, name, private_only=False): super().contribute_to_class(cls, name) if self.choices: fieldname = self.name choicedict = dict(self.choices) def func(self): value = getattr(self, fieldname) if not isinstance(value, list): value = [value] return ", ".join([force_str(choicedict.get(i, i)) for i in value]) setattr(cls, 'get_%s_display' % fieldname, func)
# ------------------------------------------------------------------------------ class MultipleSelectFormField(TypedMultipleChoiceField): widget = CheckboxSelectMultiple # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------