diff options
Diffstat (limited to 'djangorestframework/fields.py')
| -rw-r--r-- | djangorestframework/fields.py | 446 | 
1 files changed, 0 insertions, 446 deletions
| diff --git a/djangorestframework/fields.py b/djangorestframework/fields.py deleted file mode 100644 index 13b0e37d..00000000 --- a/djangorestframework/fields.py +++ /dev/null @@ -1,446 +0,0 @@ -import copy -import datetime -import inspect -import warnings - -from django.core import validators -from django.core.exceptions import ValidationError -from django.conf import settings -from django.db import DEFAULT_DB_ALIAS -from django.db.models.related import RelatedObject -from django.utils.encoding import is_protected_type, smart_unicode -from django.utils.translation import ugettext_lazy as _ -from djangorestframework.compat import parse_date, parse_datetime -from djangorestframework.compat import timezone - - -def is_simple_callable(obj): -    """ -    True if the object is a callable that takes no arguments. -    """ -    return ( -        (inspect.isfunction(obj) and not inspect.getargspec(obj)[0]) or -        (inspect.ismethod(obj) and len(inspect.getargspec(obj)[0]) <= 1) -    ) - - -class Field(object): -    creation_counter = 0 -    default_validators = [] -    default_error_messages = { -        'required': _('This field is required.'), -        'invalid': _('Invalid value.'), -    } -    empty = '' - -    def __init__(self, source=None, readonly=False, required=None, -                 validators=[], error_messages=None): -        self.parent = None - -        self.creation_counter = Field.creation_counter -        Field.creation_counter += 1 - -        self.source = source -        self.readonly = readonly -        self.required = not(readonly) - -        messages = {} -        for c in reversed(self.__class__.__mro__): -            messages.update(getattr(c, 'default_error_messages', {})) -        messages.update(error_messages or {}) -        self.error_messages = messages - -        self.validators = self.default_validators + validators - -    def initialize(self, parent, model_field=None): -        """ -        Called to set up a field prior to field_to_native or field_from_native. - -        parent - The parent serializer. -        model_field - The model field this field corrosponds to, if one exists. -        """ -        self.parent = parent -        self.root = parent.root or parent -        self.context = self.root.context -        if model_field: -            self.model_field = model_field - -    def validate(self, value): -        pass -        # if value in validators.EMPTY_VALUES and self.required: -        #     raise ValidationError(self.error_messages['required']) - -    def run_validators(self, value): -        if value in validators.EMPTY_VALUES: -            return -        errors = [] -        for v in self.validators: -            try: -                v(value) -            except ValidationError as e: -                if hasattr(e, 'code') and e.code in self.error_messages: -                    message = self.error_messages[e.code] -                    if e.params: -                        message = message % e.params -                    errors.append(message) -                else: -                    errors.extend(e.messages) -        if errors: -            raise ValidationError(errors) - -    def field_from_native(self, data, field_name, into): -        """ -        Given a dictionary and a field name, updates the dictionary `into`, -        with the field and it's deserialized value. -        """ -        if self.readonly: -            return - -        try: -            native = data[field_name] -        except KeyError: -            return  # TODO Consider validation behaviour, 'required' opt etc... - -        value = self.from_native(native) -        if self.source == '*': -            if value: -                into.update(value) -        else: -            self.validate(value) -            self.run_validators(value) -            into[self.source or field_name] = value - -    def from_native(self, value): -        """ -        Reverts a simple representation back to the field's value. -        """ -        if hasattr(self, 'model_field'): -            try: -                return self.model_field.rel.to._meta.get_field(self.model_field.rel.field_name).to_python(value) -            except: -                return self.model_field.to_python(value) -        return value - -    def field_to_native(self, obj, field_name): -        """ -        Given and object and a field name, returns the value that should be -        serialized for that field. -        """ -        if obj is None: -            return self.empty - -        if self.source == '*': -            return self.to_native(obj) - -        self.obj = obj  # Need to hang onto this in the case of model fields -        if hasattr(self, 'model_field'): -            return self.to_native(self.model_field._get_val_from_obj(obj)) - -        return self.to_native(getattr(obj, self.source or field_name)) - -    def to_native(self, value): -        """ -        Converts the field's value into it's simple representation. -        """ -        if is_simple_callable(value): -            value = value() - -        if is_protected_type(value): -            return value -        elif hasattr(self, 'model_field'): -            return self.model_field.value_to_string(self.obj) -        return smart_unicode(value) - -    def attributes(self): -        """ -        Returns a dictionary of attributes to be used when serializing to xml. -        """ -        try: -            return { -                "type": self.model_field.get_internal_type() -            } -        except AttributeError: -            return {} - - -class RelatedField(Field): -    """ -    A base class for model related fields or related managers. - -    Subclass this and override `convert` to define custom behaviour when -    serializing related objects. -    """ - -    def field_to_native(self, obj, field_name): -        obj = getattr(obj, field_name) -        if obj.__class__.__name__ in ('RelatedManager', 'ManyRelatedManager'): -            return [self.to_native(item) for item in obj.all()] -        return self.to_native(obj) - -    def attributes(self): -        try: -            return { -                "rel": self.model_field.rel.__class__.__name__, -                "to": smart_unicode(self.model_field.rel.to._meta) -            } -        except AttributeError: -            return {} - - -class PrimaryKeyRelatedField(RelatedField): -    """ -    Serializes a model related field or related manager to a pk value. -    """ - -    # Note the we use ModelRelatedField's implementation, as we want to get the -    # raw database value directly, since that won't involve another -    # database lookup. -    # -    # An alternative implementation would simply be this... -    # -    # class PrimaryKeyRelatedField(RelatedField): -    #     def to_native(self, obj): -    #         return obj.pk - -    def to_native(self, pk): -        """ -        Simply returns the object's pk.  You can subclass this method to -        provide different serialization behavior of the pk. -        (For example returning a URL based on the model's pk.) -        """ -        return pk - -    def field_to_native(self, obj, field_name): -        try: -            obj = obj.serializable_value(field_name) -        except AttributeError: -            field = obj._meta.get_field_by_name(field_name)[0] -            obj = getattr(obj, field_name) -            if obj.__class__.__name__ == 'RelatedManager': -                return [self.to_native(item.pk) for item in obj.all()] -            elif isinstance(field, RelatedObject): -                return self.to_native(obj.pk) -            raise -        if obj.__class__.__name__ == 'ManyRelatedManager': -            return [self.to_native(item.pk) for item in obj.all()] -        return self.to_native(obj) - -    def field_from_native(self, data, field_name, into): -        value = data.get(field_name) -        if hasattr(value, '__iter__'): -            into[field_name] = [self.from_native(item) for item in value] -        else: -            into[field_name + '_id'] = self.from_native(value) - - -class NaturalKeyRelatedField(RelatedField): -    """ -    Serializes a model related field or related manager to a natural key value. -    """ -    is_natural_key = True  # XML renderer handles these differently - -    def to_native(self, obj): -        if hasattr(obj, 'natural_key'): -            return obj.natural_key() -        return obj - -    def field_from_native(self, data, field_name, into): -        value = data.get(field_name) -        into[self.model_field.attname] = self.from_native(value) - -    def from_native(self, value): -        # TODO: Support 'using' : db = options.pop('using', DEFAULT_DB_ALIAS) -        manager = self.model_field.rel.to._default_manager -        manager = manager.db_manager(DEFAULT_DB_ALIAS) -        return manager.get_by_natural_key(*value).pk - - -class BooleanField(Field): -    default_error_messages = { -        'invalid': _(u"'%s' value must be either True or False."), -    } - -    def from_native(self, value): -        if value in (True, False): -            # if value is 1 or 0 than it's equal to True or False, but we want -            # to return a true bool for semantic reasons. -            return bool(value) -        if value in ('t', 'True', '1'): -            return True -        if value in ('f', 'False', '0'): -            return False -        raise ValidationError(self.error_messages['invalid'] % value) - - -class CharField(Field): -    def __init__(self, max_length=None, min_length=None, *args, **kwargs): -        self.max_length, self.min_length = max_length, min_length -        super(CharField, self).__init__(*args, **kwargs) -        if min_length is not None: -            self.validators.append(validators.MinLengthValidator(min_length)) -        if max_length is not None: -            self.validators.append(validators.MaxLengthValidator(max_length)) - -    def from_native(self, value): -        if isinstance(value, basestring) or value is None: -            return value -        return smart_unicode(value) - - -class EmailField(CharField): -    default_error_messages = { -        'invalid': _('Enter a valid e-mail address.'), -    } -    default_validators = [validators.validate_email] - -    def from_native(self, value): -        return super(EmailField, self).from_native(value).strip() - -    def __deepcopy__(self, memo): -        result = copy.copy(self) -        memo[id(self)] = result -        #result.widget = copy.deepcopy(self.widget, memo) -        result.validators = self.validators[:] -        return result - - -class DateField(Field): -    default_error_messages = { -        'invalid': _(u"'%s' value has an invalid date format. It must be " -                     u"in YYYY-MM-DD format."), -        'invalid_date': _(u"'%s' value has the correct format (YYYY-MM-DD) " -                          u"but it is an invalid date."), -    } -    empty = None - -    def from_native(self, value): -        if value is None: -            return value -        if isinstance(value, datetime.datetime): -            if timezone and settings.USE_TZ and timezone.is_aware(value): -                # Convert aware datetimes to the default time zone -                # before casting them to dates (#17742). -                default_timezone = timezone.get_default_timezone() -                value = timezone.make_naive(value, default_timezone) -            return value.date() -        if isinstance(value, datetime.date): -            return value - -        try: -            parsed = parse_date(value) -            if parsed is not None: -                return parsed -        except ValueError: -            msg = self.error_messages['invalid_date'] % value -            raise ValidationError(msg) - -        msg = self.error_messages['invalid'] % value -        raise ValidationError(msg) - - -class DateTimeField(Field): -    default_error_messages = { -        'invalid': _(u"'%s' value has an invalid format. It must be in " -                     u"YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format."), -        'invalid_date': _(u"'%s' value has the correct format " -                          u"(YYYY-MM-DD) but it is an invalid date."), -        'invalid_datetime': _(u"'%s' value has the correct format " -                              u"(YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]) " -                              u"but it is an invalid date/time."), -    } -    empty = None - -    def from_native(self, value): -        if value is None: -            return value -        if isinstance(value, datetime.datetime): -            return value -        if isinstance(value, datetime.date): -            value = datetime.datetime(value.year, value.month, value.day) -            if settings.USE_TZ: -                # For backwards compatibility, interpret naive datetimes in -                # local time. This won't work during DST change, but we can't -                # do much about it, so we let the exceptions percolate up the -                # call stack. -                warnings.warn(u"DateTimeField received a naive datetime (%s)" -                              u" while time zone support is active." % value, -                              RuntimeWarning) -                default_timezone = timezone.get_default_timezone() -                value = timezone.make_aware(value, default_timezone) -            return value - -        try: -            parsed = parse_datetime(value) -            if parsed is not None: -                return parsed -        except ValueError: -            msg = self.error_messages['invalid_datetime'] % value -            raise ValidationError(msg) - -        try: -            parsed = parse_date(value) -            if parsed is not None: -                return datetime.datetime(parsed.year, parsed.month, parsed.day) -        except ValueError: -            msg = self.error_messages['invalid_date'] % value -            raise ValidationError(msg) - -        msg = self.error_messages['invalid'] % value -        raise ValidationError(msg) - - -class IntegerField(Field): -    default_error_messages = { -        'invalid': _('Enter a whole number.'), -        'max_value': _('Ensure this value is less than or equal to %(limit_value)s.'), -        'min_value': _('Ensure this value is greater than or equal to %(limit_value)s.'), -    } - -    def __init__(self, max_value=None, min_value=None, *args, **kwargs): -        self.max_value, self.min_value = max_value, min_value -        super(IntegerField, self).__init__(*args, **kwargs) - -        if max_value is not None: -            self.validators.append(validators.MaxValueValidator(max_value)) -        if min_value is not None: -            self.validators.append(validators.MinValueValidator(min_value)) - -    def from_native(self, value): -        if value in validators.EMPTY_VALUES: -            return None -        try: -            value = int(str(value)) -        except (ValueError, TypeError): -            raise ValidationError(self.error_messages['invalid']) -        return value - - -class FloatField(Field): -    default_error_messages = { -        'invalid': _("'%s' value must be a float."), -    } - -    def from_native(self, value): -        if value is None: -            return value -        try: -            return float(value) -        except (TypeError, ValueError): -            msg = self.error_messages['invalid'] % value -            raise ValidationError(msg) - -# field_mapping = { -#     models.AutoField: IntegerField, -#     models.BooleanField: BooleanField, -#     models.CharField: CharField, -#     models.DateTimeField: DateTimeField, -#     models.DateField: DateField, -#     models.BigIntegerField: IntegerField, -#     models.IntegerField: IntegerField, -#     models.PositiveIntegerField: IntegerField, -#     models.FloatField: FloatField -# } - - -# def modelfield_to_serializerfield(field): -#     return field_mapping.get(type(field), Field) | 
