Ticket #14694: 14694-defer-reverse-relations-r17008.diff
File 14694-defer-reverse-relations-r17008.diff, 5.6 KB (added by , 13 years ago) |
---|
-
django/db/models/sql/query.py
16 16 from django.db.models import signals 17 17 from django.db.models.fields import FieldDoesNotExist 18 18 from django.db.models.query_utils import InvalidQuery 19 from django.db.models.related import RelatedObject 19 20 from django.db.models.sql import aggregates as base_aggregates_module 20 21 from django.db.models.sql.constants import * 21 22 from django.db.models.sql.datastructures import EmptyResultSet, Empty, MultiJoin … … 580 581 for name in parts[:-1]: 581 582 old_model = cur_model 582 583 source = opts.get_field_by_name(name)[0] 583 cur_model = opts.get_field_by_name(name)[0].rel.to 584 if isinstance(source, RelatedObject): 585 cur_model = source.model 586 else: 587 cur_model = source.rel.to 584 588 opts = cur_model._meta 585 589 # Even if we're "just passing through" this model, we must add 586 590 # both the current model's pk and the related reference field 587 # to the things we select. 588 must_include[old_model].add(source) 591 # (if it's not a reverse relation) to the things we select. 592 if not isinstance(source, RelatedObject): 593 must_include[old_model].add(source) 589 594 add_to_dict(must_include, cur_model, opts.pk) 590 595 field, model, _, _ = opts.get_field_by_name(parts[-1]) 591 596 if model is None: … … 630 635 for model, values in seen.iteritems(): 631 636 callback(target, model, values) 632 637 633 634 638 def deferred_to_columns_cb(self, target, model, fields): 635 639 """ 636 640 Callback used by deferred_to_columns(). The "target" parameter should … … 642 646 for field in fields: 643 647 target[table].add(field.column) 644 648 645 646 649 def table_alias(self, table_name, create=False): 647 650 """ 648 651 Returns a table alias for the given table_name and whether this is a -
django/db/models/query.py
1393 1393 # If the related object exists, populate 1394 1394 # the descriptor cache. 1395 1395 setattr(rel_obj, f.get_cache_name(), obj) 1396 # Now populate all the non-local field values 1397 # on the related object 1398 for rel_field, rel_model in rel_obj._meta.get_fields_with_model(): 1396 # Now populate all the non-local field values on the related 1397 # object. If this object has deferred fields, we need to use 1398 # the opts from the original model to get non-local fields 1399 # correctly. 1400 opts = rel_obj._meta 1401 if getattr(rel_obj, '_deferred'): 1402 opts = opts.proxy_for_model._meta 1403 for rel_field, rel_model in opts.get_fields_with_model(): 1399 1404 if rel_model is not None: 1400 1405 setattr(rel_obj, rel_field.attname, getattr(obj, rel_field.attname)) 1401 1406 # populate the field cache for any related object -
tests/regressiontests/defer_regress/tests.py
9 9 from django.test import TestCase 10 10 11 11 from .models import (ResolveThis, Item, RelatedItem, Child, Leaf, Proxy, 12 SimpleItem, Feature )12 SimpleItem, Feature, OneToOneItem) 13 13 14 14 15 15 class DeferRegressionTest(TestCase): … … 110 110 Feature, 111 111 Item, 112 112 Leaf, 113 OneToOneItem, 113 114 Proxy, 114 115 RelatedItem, 115 116 ResolveThis, … … 141 142 "Leaf_Deferred_name_value", 142 143 "Leaf_Deferred_second_child_value", 143 144 "Leaf_Deferred_value", 145 "OneToOneItem", 144 146 "Proxy", 145 147 "RelatedItem", 146 148 "RelatedItem_Deferred_", … … 174 176 qs = ResolveThis.objects.defer('num') 175 177 self.assertEqual(1, qs.count()) 176 178 self.assertEqual('Foobar', qs[0].name) 179 180 def test_reverse_one_to_one_relations(self): 181 item = Item.objects.create(name="first", value=42) 182 OneToOneItem.objects.create(item=item, name="second") 183 self.assertEqual(len(Item.objects.all()), 1) 184 self.assertEqual(len(Item.objects.defer('one_to_one_item__name')), 1) 185 self.assertEqual(len(Item.objects.select_related('one_to_one_item')), 1) 186 self.assertEqual(len(Item.objects.select_related('one_to_one_item').defer('one_to_one_item__name')), 1) 187 self.assertEqual(len(Item.objects.select_related('one_to_one_item').defer('value')), 1) -
tests/regressiontests/defer_regress/models.py
47 47 48 48 class Feature(models.Model): 49 49 item = models.ForeignKey(SimpleItem) 50 51 class OneToOneItem(models.Model): 52 item = models.OneToOneField(Item, related_name="one_to_one_item") 53 name = models.CharField(max_length=15)