diff --git a/django/db/models/base.py b/django/db/models/base.py index 013dc96e92..01e2ca7011 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -272,14 +272,14 @@ class Model(object): for field in fields_iter: is_related_object = False + # This slightly odd construct is so that we can access any + # data-descriptor object (DeferredAttribute) without triggering its + # __get__ method. + if (field.attname not in kwargs and + isinstance(self.__class__.__dict__.get(field.attname), DeferredAttribute)): + # This field will be populated on request. + continue if kwargs: - # This slightly odd construct is so that we can access any - # data-descriptor object (DeferredAttribute) without triggering - # its __get__ method. - if (field.attname not in kwargs and - isinstance(self.__class__.__dict__.get(field.attname), DeferredAttribute)): - # This field will be populated on request. - continue if isinstance(field.rel, ManyToOneRel): try: # Assume object instance was passed in. diff --git a/tests/regressiontests/defer_regress/__init__.py b/tests/regressiontests/defer_regress/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/regressiontests/defer_regress/models.py b/tests/regressiontests/defer_regress/models.py new file mode 100644 index 0000000000..c46d7ce176 --- /dev/null +++ b/tests/regressiontests/defer_regress/models.py @@ -0,0 +1,47 @@ +""" +Regression tests for defer() / only() behavior. +""" + +from django.conf import settings +from django.db import connection, models + +class Item(models.Model): + name = models.CharField(max_length=10) + text = models.TextField(default="xyzzy") + value = models.IntegerField() + other_value = models.IntegerField(default=0) + + def __unicode__(self): + return self.name + +__test__ = {"regression_tests": """ +Deferred fields should really be deferred and not accidentally use the field's +default value just because they aren't passed to __init__. + +>>> settings.DEBUG = True +>>> _ = Item.objects.create(name="first", value=42) +>>> obj = Item.objects.only("name", "other_value").get(name="first") + +# Accessing "name" doesn't trigger a new database query. Accessing "value" or +# "text" should. +>>> num = len(connection.queries) +>>> obj.name +u"first" +>>> obj.other_value +0 +>>> len(connection.queries) == num +True +>>> obj.value +42 +>>> len(connection.queries) == num + 1 # Effect of values lookup. +True +>>> obj.text +u"xyzzy" +>>> len(connection.queries) == num + 2 # Effect of text lookup. +True + +>>> settings.DEBUG = False + +""" +} +