Source code for fobi.contrib.apps.drf_integration.fields

import copy

import six
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
from rest_framework.fields import (  # ModelField,
    ChoiceField,
    Field,
    MultipleChoiceField,
    empty,
)

__title__ = "fobi.contrib.apps.drf_integration.fields"
__author__ = "Artur Barseghyan <artur.barseghyan@gmail.com>"
__copyright__ = "2016-2019 Artur Barseghyan"
__license__ = "GPL 2.0/LGPL 2.1"
__all__ = (
    "ContentImageField",
    "ContentMarkdownField",
    "ContentRichTextField",
    "ContentTextField",
    "ContentVideoField",
    "ModelChoiceField",
    "ModelMultipleChoiceField",
    "MultipleChoiceWithMaxField",
    "NoneField",
)

# *****************************************************************************
# *****************************************************************************
# ************************** Additional DRF fields ****************************
# *****************************************************************************
# *****************************************************************************

# *****************************************************************************
# *************************** Traditional fields ******************************


[docs]class MultipleChoiceWithMaxField(MultipleChoiceField): """MultipleChoiceWithMaxField.""" default_error_messages = copy.copy( MultipleChoiceField.default_error_messages ) default_error_messages.update( { "max_choices": _("Max number of choices reached."), } ) def __init__(self, *args, **kwargs): self.max_choices = kwargs.pop("max_choices", None) super(MultipleChoiceWithMaxField, self).__init__(*args, **kwargs)
[docs] def to_internal_value(self, data): if self.max_choices: if len(data) > self.max_choices: self.fail("max_choices") return super(MultipleChoiceWithMaxField, self).to_internal_value(data)
class ModelChoiceFieldMixin(object): """Model choice field mixin.""" def get_choices(self): """Get choices.""" choices = [] if self.model_attr: for _choice in self.queryset: choices.append((_choice.pk, getattr(_choice, self.model_attr))) else: for _choice in self.queryset: choices.append((_choice.pk, six.text_type(_choice))) return choices
[docs]class ModelChoiceField(ChoiceField, ModelChoiceFieldMixin): """Model choice field.""" def __init__(self, *args, **kwargs): self.queryset = kwargs.pop("queryset", None) self.model_attr = kwargs.pop("model_attr", None) choices = self.get_choices() kwargs.update({"choices": choices}) super(ModelChoiceField, self).__init__(*args, **kwargs)
[docs]class ModelMultipleChoiceField(MultipleChoiceField, ModelChoiceFieldMixin): """Model choice field.""" def __init__(self, *args, **kwargs): self.queryset = kwargs.pop("queryset", None) self.model_attr = kwargs.pop("model_attr", None) choices = self.get_choices() kwargs.update({"choices": choices}) super(ModelMultipleChoiceField, self).__init__(*args, **kwargs)
# ***************************************************************************** # ************************* Presentational fields ***************************** # *****************************************************************************
[docs]class NoneField(Field): """NoneField.""" default_error_messages = {} initial = "" default_empty_html = "" def __init__(self, **kwargs): self.allow_blank = True self.trim_whitespace = kwargs.pop("trim_whitespace", True) self.raw_data = kwargs.pop("raw_data", {}) super(NoneField, self).__init__(**kwargs)
[docs] def run_validation(self, data=empty): return ""
[docs] def to_internal_value(self, data): # We're lenient with allowing basic numerics to be coerced into # strings, but other types should fail. Eg. unclear if booleans # should represent as `true` or `True`, and composites such as lists # are likely user error. _not_isinstance_str_int_float = not isinstance( data, six.string_types + six.integer_types + (float,) ) if isinstance(data, bool) or _not_isinstance_str_int_float: self.fail("invalid") value = six.text_type(data) return value.strip() if self.trim_whitespace else value
[docs] def to_representation(self, value): return mark_safe(six.text_type(value))
[docs]class ContentTextField(NoneField): """Content text field."""
[docs]class ContentRichTextField(NoneField): """Content rich text field."""
[docs]class ContentMarkdownField(NoneField): """Content markdown field."""
[docs]class ContentImageField(NoneField): """Content image field."""
[docs]class ContentVideoField(NoneField): """Content video field."""