Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

[soc2010/query-refactor] Improved the ListField implementation, and a…

…dded an EmbeddedModelField.

git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2010/query-refactor@13564 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit c7bd48cb9f645e5ff07d1e68b86130e3bb2b043f 1 parent 9b263c6
@alex alex authored
View
4 django/contrib/mongodb/compiler.py
@@ -172,6 +172,10 @@ def update(self, result_type):
vals = {}
for field, o, value in self.query.values:
+ if hasattr(value, 'prepare_database_save'):
+ value = value.prepare_database_save(field)
+ else:
+ value = field.get_db_prep_save(value, connection=self.connection)
if hasattr(value, "evaluate"):
assert value.connector in (value.ADD, value.SUB)
assert not value.negated
View
2  django/db/models/__init__.py
@@ -13,7 +13,7 @@
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.
View
57 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 @@ def get_db_prep_lookup(self, lookup_type, value, connection, prepared=False):
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)
View
1  django/utils/encoding.py
@@ -47,6 +47,7 @@ def is_protected_type(obj):
return isinstance(obj, (
types.NoneType,
int, long,
+ list,
datetime.datetime, datetime.date, datetime.time,
float, Decimal)
)
View
20 tests/regressiontests/mongodb/models.py
@@ -31,3 +31,23 @@ class Post(models.Model):
magic_numbers = models.ListField(
models.IntegerField()
)
+
+
+class Revision(models.Model):
+ number = models.IntegerField()
+ content = models.TextField()
+
+
+class AuthenticatedRevision(Revision):
+ # This is a really stupid way to add optional authentication, but it serves
+ # its purpose.
+ author = models.CharField(max_length=100)
+
+
+class WikiPage(models.Model):
+ id = models.NativeAutoField(primary_key=True)
+ title = models.CharField(max_length=255)
+
+ revisions = models.ListField(
+ models.EmbeddedModel(Revision)
+ )
View
57 tests/regressiontests/mongodb/tests.py
@@ -1,8 +1,9 @@
+from django.core.exceptions import ValidationError
from django.db import connection, UnsupportedDatabaseOperation
from django.db.models import Count, Sum, F, Q
from django.test import TestCase
-from models import Artist, Group, Post
+from models import Artist, Group, Post, WikiPage, Revision, AuthenticatedRevision
class MongoTestCase(TestCase):
@@ -398,6 +399,9 @@ def test_unsupported_ops(self):
)
def test_list_field(self):
+ p = Post()
+ self.assertEqual(p.tags, [])
+
p = Post.objects.create(
title="Django ORM grows MongoDB support",
tags=["python", "django", "mongodb", "web"]
@@ -428,7 +432,7 @@ def test_list_field(self):
lambda p: p.title
)
- self.assertRaises(ValueError,
+ self.assertRaises(ValidationError,
lambda: Post.objects.create(magic_numbers=["a"])
)
@@ -448,3 +452,52 @@ def test_list_field(self):
],
lambda p: p.title,
)
+
+ def test_embedded_model(self):
+ page = WikiPage(title="Django")
+ page.revisions.append(
+ Revision(number=1, content="Django is a Python")
+ )
+ page.revisions.append(
+ Revision(number=2, content="Django is a Python web framework.")
+ )
+
+ page.save()
+
+ page = WikiPage.objects.get(pk=page.pk)
+ self.assertEqual(len(page.revisions), 2)
+ self.assertEqual(
+ [(r.number, r.content) for r in page.revisions],
+ [(1, "Django is a Python"), (2, "Django is a Python web framework.")]
+ )
+
+ self.assertEqual(Revision.objects.count(), 0)
+
+ self.assertRaises(ValidationError,
+ lambda: WikiPage.objects.create(title="Python", revisions=14)
+ )
+ self.assertRaises(ValidationError,
+ lambda: WikiPage.objects.create(title="Python", revisions=[14])
+ )
+
+ page = WikiPage.objects.create(title="Python", revisions=[
+ Revision(number=1, content="Python was created by Guido van Rossum.")
+ ])
+ page = WikiPage.objects.get(pk=page.pk)
+ self.assertEqual(len(page.revisions), 1)
+
+ page.revisions.append(
+ AuthenticatedRevision(number=2, content="Python is a trap.", author="Rasmus Lerdorf"),
+ )
+
+ page.save()
+ self.assertEqual(len(page.revisions), 2)
+ self.assertEqual(page.revisions[-1].author, "Rasmus Lerdorf")
+
+ page = WikiPage.objects.get(pk=page.pk)
+ self.assertEqual(len(page.revisions), 2)
+ self.assertTrue(isinstance(page.revisions[-1], AuthenticatedRevision))
+ self.assertEqual(page.revisions[-1].author, "Rasmus Lerdorf")
+
+ page.revisions.append(14)
+ self.assertRaises(ValidationError, page.save)
Please sign in to comment.
Something went wrong with that request. Please try again.