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 (
    ChoiceField,
    Field,
    empty,
    # ModelField,
    MultipleChoiceField,
)

__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."""