id,summary,reporter,owner,description,type,status,component,version,severity,resolution,keywords,cc,stage,has_patch,needs_docs,needs_tests,needs_better_patch,easy,ui_ux 17485,Queries with both deferred fields and select_related defer field.name instead of field.attname,Michal Petrucha,Anssi Kääriäinen,"When deferring `ForeignKey` fields in conjunction with `select_related`, Django creates a `DeferredAttribute` for the field's `name` instead of its `attname`. This results in its `ReverseSingleRelatedObjectDescriptor` being overriden and thus stripping the model instance of most of this field's functionality. Consider the following models (taken from regressiontests.queries): {{{#!python class Celebrity(models.Model): name = models.CharField(""Name"", max_length=20) greatest_fan = models.ForeignKey(""Fan"", null=True, unique=True) def __unicode__(self): return self.name class Fan(models.Model): fan_of = models.ForeignKey(Celebrity) }}} Let's play around with it in the shell for a bit: {{{ >>> Celebrity.objects.create(name=""Joe"") >>> obj = Celebrity.objects.all().defer('greatest_fan').select_related('greatest_fan').get() >>> print obj.__class__.__dict__ { '__module__': 'subclassfktest.models', '_meta': , 'objects': , 'MultipleObjectsReturned': , '_base_manager': , 'greatest_fan': , 'DoesNotExist': , '__doc__': 'Celebrity_Deferred_greatest_fan(id, name, greatest_fan_id)', '_default_manager': , '_deferred': True } }}} We can see that the deferred atribute is at `greatest_fan` instead of `greatest_fan_id` and the `ReverseSingleRelatedObjectDescriptor` is not present at all. The following is just to show that the model instance is really broken because of this: {{{ >>> print obj.greatest_fan None >>> f = Fan.objects.create(fan_of=obj) >>> obj.greatest_fan = f >>> obj.save() >>> obj2 = Celebrity.objects.get() >>> f.id 1 >>> print obj2.greatest_fan_id # Should be 1 None }}} An interesting thing, though, is that the instance gives access to the right related object instance even without a working `ReverseSingleRelatedObjectDescriptor`: {{{ >>> obj2.greatest_fan = f >>> obj2.save() >>> obj = Celebrity.objects.all().defer('greatest_fan').select_related('greatest_fan').get() >>> obj.greatest_fan.id 1 >>> obj.__dict__ {'_greatest_fan_cache': , 'name': u'Joe', 'greatest_fan_id': None, '_state': , 'greatest_fan': , 'id': 1} }}} Anyway, the `_id` attribute is still never set to the correct value. The fix for this behavior is a one-liner, see attachment. It makes sure to defer the field's `attname` even in this case (in all other cases where `deferred_class_factory` is called, `attnames` are used). There are side effects, though. Actually, this bug was hiding another one for which even tests exist but because of this one they pass. The first test failure is `test_basic` in `regressiontests.defer_regress.tests.DeferRegressionTest` which is quite obvious, it lists the incorrect model name caused by this bug and is fixed easily (since it is actually an incorrect test). The other one, though, is not that simple: `test_defer` in `modeltests.defer.tests.DeferTests`. More precisely the following two lines: {{{#!python # DOES THIS WORK? self.assert_delayed(qs.only(""name"").select_related(""related"")[0], 1) self.assert_delayed(qs.defer(""related"").select_related(""related"")[0], 0) }}} where `related` is a ForeignKey. These have been around for a while and the only reason they passed until now is that `assert_delayed` checks the `attname` of each field whether it is deferred or not. In this case, however, the `attname` is obviously not deferred, since the `name` is in its stead. The question is, what should we do with these two tests? Do we want to fix them in one go with this bug or file a new ticket and temporarily comment out the two failing test lines?",Bug,closed,"Database layer (models, ORM)",dev,Release blocker,fixed,defer select_related,niwi@… real.human@…,Ready for checkin,1,0,0,0,0,0