aboutsummaryrefslogtreecommitdiffstats
path: root/djangorestframework/fields.py
diff options
context:
space:
mode:
Diffstat (limited to 'djangorestframework/fields.py')
-rw-r--r--djangorestframework/fields.py446
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)