Author: russellm
Date: 2009-06-06 01:14:05 -0500 (Sat, 06 Jun 2009)
New Revision: 10926

Modified:
   django/trunk/django/db/models/query.py
   django/trunk/django/db/models/sql/query.py
   django/trunk/tests/modeltests/defer/models.py
Log:
Fixed #10572 -- Corrected the operation of the defer() and only() clauses when 
used on inherited models.

Modified: django/trunk/django/db/models/query.py
===================================================================
--- django/trunk/django/db/models/query.py      2009-06-05 20:58:34 UTC (rev 
10925)
+++ django/trunk/django/db/models/query.py      2009-06-06 06:14:05 UTC (rev 
10926)
@@ -190,7 +190,25 @@
         index_start = len(extra_select)
         aggregate_start = index_start + len(self.model._meta.fields)
 
-        load_fields = only_load.get(self.model)
+        load_fields = []
+        # If only/defer clauses have been specified,
+        # build the list of fields that are to be loaded.
+        if only_load:
+            for field, model in self.model._meta.get_fields_with_model():
+                if model is None:
+                    model = self.model
+                if field == self.model._meta.pk:
+                    # Record the index of the primary key when it is found
+                    pk_idx = len(load_fields)
+                try:
+                    if field.name in only_load[model]:
+                        # Add a field that has been explicitly included
+                        load_fields.append(field.name)
+                except KeyError:
+                    # Model wasn't explicitly listed in the only_load table
+                    # Therefore, we need to load all fields from this model
+                    load_fields.append(field.name)
+
         skip = None
         if load_fields and not fill_cache:
             # Some fields have been deferred, so we have to initialise

Modified: django/trunk/django/db/models/sql/query.py
===================================================================
--- django/trunk/django/db/models/sql/query.py  2009-06-05 20:58:34 UTC (rev 
10925)
+++ django/trunk/django/db/models/sql/query.py  2009-06-06 06:14:05 UTC (rev 
10926)
@@ -635,10 +635,10 @@
             # models.
             workset = {}
             for model, values in seen.iteritems():
-                for field, f_model in model._meta.get_fields_with_model():
+                for field in model._meta.local_fields:
                     if field in values:
                         continue
-                    add_to_dict(workset, f_model or model, field)
+                    add_to_dict(workset, model, field)
             for model, values in must_include.iteritems():
                 # If we haven't included a model in workset, we don't add the
                 # corresponding must_include fields for that model, since an
@@ -657,6 +657,12 @@
                     # included any fields, we have to make sure it's mentioned
                     # so that only the "must include" fields are pulled in.
                     seen[model] = values
+            # Now ensure that every model in the inheritance chain is mentioned
+            # in the parent list. Again, it must be mentioned to ensure that
+            # only "must include" fields are pulled in.
+            for model in orig_opts.get_parent_list():
+                if model not in seen:
+                    seen[model] = set()
             for model, values in seen.iteritems():
                 callback(target, model, values)
 

Modified: django/trunk/tests/modeltests/defer/models.py
===================================================================
--- django/trunk/tests/modeltests/defer/models.py       2009-06-05 20:58:34 UTC 
(rev 10925)
+++ django/trunk/tests/modeltests/defer/models.py       2009-06-06 06:14:05 UTC 
(rev 10926)
@@ -17,6 +17,12 @@
     def __unicode__(self):
         return self.name
 
+class Child(Primary):
+    pass
+
+class BigChild(Primary):
+    other = models.CharField(max_length=50)
+
 def count_delayed_fields(obj, debug=False):
     """
     Returns the number of delayed attributes on the given model instance.
@@ -33,7 +39,7 @@
 
 __test__ = {"API_TEST": """
 To all outward appearances, instances with deferred fields look the same as
-normal instances when we examine attribut values. Therefore we test for the
+normal instances when we examine attribute values. Therefore we test for the
 number of deferred fields on returned instances (by poking at the internals),
 as a way to observe what is going on.
 
@@ -98,5 +104,89 @@
 >>> Primary.objects.all()
 [<Primary: a new name>]
 
+# Regression for #10572 - A subclass with no extra fields can defer fields 
from the base class
+>>> _ = Child.objects.create(name="c1", value="foo", related=s1)
 
+# You can defer a field on a baseclass when the subclass has no fields
+>>> obj = Child.objects.defer("value").get(name="c1")
+>>> count_delayed_fields(obj)
+1
+>>> obj.name
+u"c1"
+>>> obj.value
+u"foo"
+>>> obj.name = "c2"
+>>> obj.save()
+
+# You can retrive a single column on a base class with no fields
+>>> obj = Child.objects.only("name").get(name="c2")
+>>> count_delayed_fields(obj)
+3
+>>> obj.name
+u"c2"
+>>> obj.value
+u"foo"
+>>> obj.name = "cc"
+>>> obj.save()
+
+>>> _ = BigChild.objects.create(name="b1", value="foo", related=s1, 
other="bar")
+
+# You can defer a field on a baseclass
+>>> obj = BigChild.objects.defer("value").get(name="b1")
+>>> count_delayed_fields(obj)
+1
+>>> obj.name
+u"b1"
+>>> obj.value
+u"foo"
+>>> obj.other
+u"bar"
+>>> obj.name = "b2"
+>>> obj.save()
+
+# You can defer a field on a subclass
+>>> obj = BigChild.objects.defer("other").get(name="b2")
+>>> count_delayed_fields(obj)
+1
+>>> obj.name
+u"b2"
+>>> obj.value
+u"foo"
+>>> obj.other
+u"bar"
+>>> obj.name = "b3"
+>>> obj.save()
+
+# You can retrieve a single field on a baseclass
+>>> obj = BigChild.objects.only("name").get(name="b3")
+>>> count_delayed_fields(obj)
+4
+>>> obj.name
+u"b3"
+>>> obj.value
+u"foo"
+>>> obj.other
+u"bar"
+>>> obj.name = "b4"
+>>> obj.save()
+
+# You can retrieve a single field on a baseclass
+>>> obj = BigChild.objects.only("other").get(name="b4")
+>>> count_delayed_fields(obj)
+4
+>>> obj.name
+u"b4"
+>>> obj.value
+u"foo"
+>>> obj.other
+u"bar"
+>>> obj.name = "bb"
+>>> obj.save()
+
+# Finally, we need to flush the app cache for the defer module.
+# Using only/defer creates some artifical entries in the app cache
+# that messes up later tests. Purge all entries, just to be sure.
+>>> from django.db.models.loading import cache
+>>> cache.app_models['defer'] = {}
+
 """}


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

Reply via email to