summaryrefslogtreecommitdiff
path: root/django/db/models
diff options
context:
space:
mode:
Diffstat (limited to 'django/db/models')
-rw-r--r--django/db/models/__init__.py2
-rw-r--r--django/db/models/fields/structures.py57
2 files changed, 57 insertions, 2 deletions
diff --git a/django/db/models/__init__.py b/django/db/models/__init__.py
index 0736648a7b..6c0161a0e9 100644
--- a/django/db/models/__init__.py
+++ b/django/db/models/__init__.py
@@ -13,7 +13,7 @@ from django.db.models.fields.subclassing import SubfieldBase
from django.db.models.fields.files import FileField, ImageField
from django.db.models.fields.related import (ForeignKey, OneToOneField,
ManyToManyField, ManyToOneRel, ManyToManyRel, OneToOneRel)
-from django.db.models.fields.structures import ListField
+from django.db.models.fields.structures import ListField, EmbeddedModel
from django.db.models import signals
# Admin stages.
diff --git a/django/db/models/fields/structures.py b/django/db/models/fields/structures.py
index 2d3822e932..b90164cc28 100644
--- a/django/db/models/fields/structures.py
+++ b/django/db/models/fields/structures.py
@@ -1,10 +1,15 @@
+from django.core.exceptions import ValidationError
+from django.db.models.loading import cache
from django.db.models.fields import Field
+from django.db.models.fields.subclassing import SubfieldBase
class ListField(Field):
+ __metaclass__ = SubfieldBase
+
def __init__(self, field_type):
self.field_type = field_type
- super(ListField, self).__init__()
+ super(ListField, self).__init__(default=[])
def get_prep_lookup(self, lookup_type, value):
return self.field_type.get_prep_lookup(lookup_type, value)
@@ -19,3 +24,53 @@ class ListField(Field):
return self.field_type.get_db_prep_lookup(
lookup_type, value, connection=connection, prepared=prepared
)
+
+ def to_python(self, value):
+ try:
+ value = iter(value)
+ except TypeError:
+ raise ValidationError("Value should be iterable")
+ return [
+ self.field_type.to_python(v)
+ for v in value
+ ]
+
+
+class EmbeddedModel(Field):
+ __metaclass__ = SubfieldBase
+
+ def __init__(self, to):
+ self.to = to
+ super(EmbeddedModel, self).__init__()
+
+ def get_db_prep_save(self, value, connection):
+ data = {}
+ if not isinstance(value, self.to):
+ raise ValidationError("Value must be an instance of %s, got %s "
+ "instead" % (self.to, value))
+ if type(value) is not self.to:
+ data["_cls"] = (value._meta.app_label, value._meta.object_name)
+ for field in value._meta.fields:
+ # If the field is a OneToOneField that makes the inheritance link,
+ # ignore it.
+ if field.rel and field.rel.parent_link:
+ continue
+ data[field.column] = field.get_db_prep_save(
+ getattr(value, field.name), connection=connection
+ )
+ return data
+
+ def to_python(self, value):
+ if isinstance(value, self.to):
+ return value
+ try:
+ value = dict(value)
+ except TypeError:
+ raise ValidationError("Value should be a dict")
+
+ if "_cls" in value:
+ cls = cache.get_model(*value.pop("_cls"))
+ else:
+ cls = self.to
+
+ return cls(**value)