Ticket #14694: 14694-defer-reverse-relations-r17462.diff
File 14694-defer-reverse-relations-r17462.diff, 6.0 KB (added by , 13 years ago) |
---|
-
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) 188 # make sure that `only()` doesn't break when we pass in a reverse relation, rather than a field on the relation. 189 self.assertEqual(len(Item.objects.only('one_to_one_item')), 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) -
django/db/models/sql/query.py
17 17 from django.db.models.expressions import ExpressionNode 18 18 from django.db.models.fields import FieldDoesNotExist 19 19 from django.db.models.query_utils import InvalidQuery 20 from django.db.models.related import RelatedObject 20 21 from django.db.models.sql import aggregates as base_aggregates_module 21 22 from django.db.models.sql.constants import * 22 23 from django.db.models.sql.datastructures import EmptyResultSet, Empty, MultiJoin … … 586 587 for name in parts[:-1]: 587 588 old_model = cur_model 588 589 source = opts.get_field_by_name(name)[0] 589 cur_model = opts.get_field_by_name(name)[0].rel.to 590 if isinstance(source, RelatedObject): 591 cur_model = source.model 592 else: 593 cur_model = source.rel.to 590 594 opts = cur_model._meta 591 595 # Even if we're "just passing through" this model, we must add 592 596 # both the current model's pk and the related reference field 593 # to the things we select. 594 must_include[old_model].add(source) 597 # (if it's not a reverse relation) to the things we select. 598 if not isinstance(source, RelatedObject): 599 must_include[old_model].add(source) 595 600 add_to_dict(must_include, cur_model, opts.pk) 596 601 field, model, _, _ = opts.get_field_by_name(parts[-1]) 597 602 if model is None: 598 603 model = cur_model 599 add_to_dict(seen, model, field) 604 if not isinstance(field, RelatedObject): 605 add_to_dict(seen, model, field) 600 606 601 607 if defer: 602 608 # We need to load all fields for each model, except those that … … 636 642 for model, values in seen.iteritems(): 637 643 callback(target, model, values) 638 644 639 640 645 def deferred_to_columns_cb(self, target, model, fields): 641 646 """ 642 647 Callback used by deferred_to_columns(). The "target" parameter should … … 648 653 for field in fields: 649 654 target[table].add(field.column) 650 655 651 652 656 def table_alias(self, table_name, create=False): 653 657 """ 654 658 Returns a table alias for the given table_name and whether this is a -
django/db/models/query.py
1413 1413 # If the related object exists, populate 1414 1414 # the descriptor cache. 1415 1415 setattr(rel_obj, f.get_cache_name(), obj) 1416 # Now populate all the non-local field values 1417 # on the related object 1418 for rel_field, rel_model in rel_obj._meta.get_fields_with_model(): 1416 # Now populate all the non-local field values on the related 1417 # object. If this object has deferred fields, we need to use 1418 # the opts from the original model to get non-local fields 1419 # correctly. 1420 opts = rel_obj._meta 1421 if getattr(rel_obj, '_deferred'): 1422 opts = opts.proxy_for_model._meta 1423 for rel_field, rel_model in opts.get_fields_with_model(): 1419 1424 if rel_model is not None: 1420 1425 setattr(rel_obj, rel_field.attname, getattr(obj, rel_field.attname)) 1421 1426 # populate the field cache for any related object