Author: Alex
Date: 2010-08-09 16:16:59 -0500 (Mon, 09 Aug 2010)
New Revision: 13564

Modified:
   django/branches/soc2010/query-refactor/django/contrib/mongodb/compiler.py
   django/branches/soc2010/query-refactor/django/db/models/__init__.py
   django/branches/soc2010/query-refactor/django/db/models/fields/structures.py
   django/branches/soc2010/query-refactor/django/utils/encoding.py
   
django/branches/soc2010/query-refactor/tests/regressiontests/mongodb/models.py
   django/branches/soc2010/query-refactor/tests/regressiontests/mongodb/tests.py
Log:
[soc2010/query-refactor]  Improved the ListField implementation, and added an 
EmbeddedModelField.

Modified: 
django/branches/soc2010/query-refactor/django/contrib/mongodb/compiler.py
===================================================================
--- django/branches/soc2010/query-refactor/django/contrib/mongodb/compiler.py   
2010-08-07 15:02:21 UTC (rev 13563)
+++ django/branches/soc2010/query-refactor/django/contrib/mongodb/compiler.py   
2010-08-09 21:16:59 UTC (rev 13564)
@@ -172,6 +172,10 @@
 
         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

Modified: django/branches/soc2010/query-refactor/django/db/models/__init__.py
===================================================================
--- django/branches/soc2010/query-refactor/django/db/models/__init__.py 
2010-08-07 15:02:21 UTC (rev 13563)
+++ django/branches/soc2010/query-refactor/django/db/models/__init__.py 
2010-08-09 21:16:59 UTC (rev 13564)
@@ -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.

Modified: 
django/branches/soc2010/query-refactor/django/db/models/fields/structures.py
===================================================================
--- 
django/branches/soc2010/query-refactor/django/db/models/fields/structures.py    
    2010-08-07 15:02:21 UTC (rev 13563)
+++ 
django/branches/soc2010/query-refactor/django/db/models/fields/structures.py    
    2010-08-09 21:16:59 UTC (rev 13564)
@@ -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 @@
         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)

Modified: django/branches/soc2010/query-refactor/django/utils/encoding.py
===================================================================
--- django/branches/soc2010/query-refactor/django/utils/encoding.py     
2010-08-07 15:02:21 UTC (rev 13563)
+++ django/branches/soc2010/query-refactor/django/utils/encoding.py     
2010-08-09 21:16:59 UTC (rev 13564)
@@ -47,6 +47,7 @@
     return isinstance(obj, (
         types.NoneType,
         int, long,
+        list,
         datetime.datetime, datetime.date, datetime.time,
         float, Decimal)
     )

Modified: 
django/branches/soc2010/query-refactor/tests/regressiontests/mongodb/models.py
===================================================================
--- 
django/branches/soc2010/query-refactor/tests/regressiontests/mongodb/models.py  
    2010-08-07 15:02:21 UTC (rev 13563)
+++ 
django/branches/soc2010/query-refactor/tests/regressiontests/mongodb/models.py  
    2010-08-09 21:16:59 UTC (rev 13564)
@@ -31,3 +31,23 @@
     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)
+    )

Modified: 
django/branches/soc2010/query-refactor/tests/regressiontests/mongodb/tests.py
===================================================================
--- 
django/branches/soc2010/query-refactor/tests/regressiontests/mongodb/tests.py   
    2010-08-07 15:02:21 UTC (rev 13563)
+++ 
django/branches/soc2010/query-refactor/tests/regressiontests/mongodb/tests.py   
    2010-08-09 21:16:59 UTC (rev 13564)
@@ -1,3 +1,4 @@
+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
@@ -2,3 +3,3 @@
 
-from models import Artist, Group, Post
+from models import Artist, Group, Post, WikiPage, Revision, 
AuthenticatedRevision
 
@@ -398,6 +399,9 @@
         )
     
     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 @@
             lambda p: p.title
         )
         
-        self.assertRaises(ValueError,
+        self.assertRaises(ValidationError,
             lambda: Post.objects.create(magic_numbers=["a"])
         )
         
@@ -448,3 +452,52 @@
             ],
             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)

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.

Reply via email to