Ticket #12734: django-defer-save.diff
File django-defer-save.diff, 9.9 KB (added by , 15 years ago) |
---|
-
django/db/models/query_utils.py
diff --git a/django/db/models/query_utils.py b/django/db/models/query_utils.py index 8e804ec..9129d95 100644
a b class DeferredAttribute(object): 183 183 Retrieves and caches the value from the datastore on the first lookup. 184 184 Returns the cached value. 185 185 """ 186 from django.db.models.fields import FieldDoesNotExist 187 186 188 assert instance is not None 187 189 cls = self.model_ref() 188 190 data = instance.__dict__ 189 191 if data.get(self.field_name, self) is self: 190 data[self.field_name] = cls._base_manager.filter(pk=instance.pk).values_list(self.field_name, flat=True).using(instance._state.db).get() 192 # self.field_name is the attname of the field, but only() takes the 193 # actual name, so we need to translate it here. 194 try: 195 cls._meta.get_field_by_name(self.field_name) 196 name = self.field_name 197 except FieldDoesNotExist: 198 name = [f.name for f in cls._meta.fields 199 if f.attname == self.field_name][0] 200 # We use only() instead of values() here because we want the 201 # various data coersion methods (to_python(), etc.) to be called 202 # here. 203 val = getattr( 204 cls._base_manager.filter(pk=instance.pk).only(name).using( 205 instance._state.db).get(), 206 self.field_name 207 ) 208 data[self.field_name] = val 191 209 return data[self.field_name] 192 210 193 211 def __set__(self, instance, value): -
new file tests/modeltests/field_subclassing/fields.py
diff --git a/tests/modeltests/field_subclassing/fields.py b/tests/modeltests/field_subclassing/fields.py new file mode 100644 index 0000000..d545b19
- + 1 from django.core.exceptions import FieldError 2 from django.db import models 3 from django.utils import simplejson as json 4 from django.utils.encoding import force_unicode 5 6 7 class Small(object): 8 """ 9 A simple class to show that non-trivial Python objects can be used as 10 attributes. 11 """ 12 def __init__(self, first, second): 13 self.first, self.second = first, second 14 15 def __unicode__(self): 16 return u'%s%s' % (force_unicode(self.first), force_unicode(self.second)) 17 18 def __str__(self): 19 return unicode(self).encode('utf-8') 20 21 class SmallField(models.Field): 22 """ 23 Turns the "Small" class into a Django field. Because of the similarities 24 with normal character fields and the fact that Small.__unicode__ does 25 something sensible, we don't need to implement a lot here. 26 """ 27 __metaclass__ = models.SubfieldBase 28 29 def __init__(self, *args, **kwargs): 30 kwargs['max_length'] = 2 31 super(SmallField, self).__init__(*args, **kwargs) 32 33 def get_internal_type(self): 34 return 'CharField' 35 36 def to_python(self, value): 37 if isinstance(value, Small): 38 return value 39 return Small(value[0], value[1]) 40 41 def get_db_prep_save(self, value): 42 return unicode(value) 43 44 def get_db_prep_lookup(self, lookup_type, value): 45 if lookup_type == 'exact': 46 return force_unicode(value) 47 if lookup_type == 'in': 48 return [force_unicode(v) for v in value] 49 if lookup_type == 'isnull': 50 return [] 51 raise FieldError('Invalid lookup type: %r' % lookup_type) 52 53 54 class JSONField(models.TextField): 55 __metaclass__ = models.SubfieldBase 56 57 description = ("JSONField automatically serializes and desializes values to " 58 "and from JSON.") 59 60 def to_python(self, value): 61 if not value: 62 return None 63 64 if isinstance(value, basestring): 65 value = json.loads(value) 66 return value 67 68 def get_db_prep_save(self, value): 69 if value is None: 70 return None 71 return json.dumps(value) -
tests/modeltests/field_subclassing/models.py
diff --git a/tests/modeltests/field_subclassing/models.py b/tests/modeltests/field_subclassing/models.py index c776146..93b30c2 100644
a b 2 2 Tests for field subclassing. 3 3 """ 4 4 5 from django.core import serializers 5 6 from django.db import models 6 7 from django.utils.encoding import force_unicode 7 from django.core import serializers8 from django.core.exceptions import FieldError9 10 class Small(object):11 """12 A simple class to show that non-trivial Python objects can be used as13 attributes.14 """15 def __init__(self, first, second):16 self.first, self.second = first, second17 18 def __unicode__(self):19 return u'%s%s' % (force_unicode(self.first), force_unicode(self.second))20 21 def __str__(self):22 return unicode(self).encode('utf-8')23 8 24 class SmallField(models.Field): 25 """ 26 Turns the "Small" class into a Django field. Because of the similarities 27 with normal character fields and the fact that Small.__unicode__ does 28 something sensible, we don't need to implement a lot here. 29 """ 30 __metaclass__ = models.SubfieldBase 9 from fields import Small, SmallField, JSONField 31 10 32 def __init__(self, *args, **kwargs):33 kwargs['max_length'] = 234 super(SmallField, self).__init__(*args, **kwargs)35 36 def get_internal_type(self):37 return 'CharField'38 39 def to_python(self, value):40 if isinstance(value, Small):41 return value42 return Small(value[0], value[1])43 44 def get_db_prep_save(self, value):45 return unicode(value)46 47 def get_db_prep_lookup(self, lookup_type, value):48 if lookup_type == 'exact':49 return force_unicode(value)50 if lookup_type == 'in':51 return [force_unicode(v) for v in value]52 if lookup_type == 'isnull':53 return []54 raise FieldError('Invalid lookup type: %r' % lookup_type)55 11 56 12 class MyModel(models.Model): 57 13 name = models.CharField(max_length=10) … … class MyModel(models.Model): 60 16 def __unicode__(self): 61 17 return force_unicode(self.name) 62 18 19 class DataModel(models.Model): 20 data = JSONField() 21 63 22 __test__ = {'API_TESTS': ur""" 64 23 # Creating a model with custom fields is done as per normal. 65 24 >>> s = Small(1, 2) -
new file tests/modeltests/field_subclassing/tests.py
diff --git a/tests/modeltests/field_subclassing/tests.py b/tests/modeltests/field_subclassing/tests.py new file mode 100644 index 0000000..731ab51
- + 1 from django.test import TestCase 2 3 from models import DataModel 4 5 6 class CustomField(TestCase): 7 def test_defer(self): 8 d = DataModel.objects.create(data=[1, 2, 3]) 9 10 self.assertTrue(isinstance(d.data, list)) 11 12 d = DataModel.objects.get(pk=d.pk) 13 self.assertTrue(isinstance(d.data, list)) 14 self.assertEqual(d.data, [1, 2, 3]) 15 16 d = DataModel.objects.defer("data").get(pk=d.pk) 17 d.save() 18 19 d = DataModel.objects.get(pk=d.pk) 20 self.assertTrue(isinstance(d.data, list)) 21 self.assertEqual(d.data, [1, 2, 3]) -
tests/regressiontests/defer_regress/models.py
diff --git a/tests/regressiontests/defer_regress/models.py b/tests/regressiontests/defer_regress/models.py index c32f5bb..08c4d62 100644
a b False 142 142 [<class 'regressiontests.defer_regress.models.Child'>, <class 'regressiontests.defer_regress.models.Item'>, <class 'regressiontests.defer_regress.models.Leaf'>, <class 'regressiontests.defer_regress.models.RelatedItem'>, <class 'regressiontests.defer_regress.models.ResolveThis'>] 143 143 144 144 >>> sorted(get_models(models.get_app('defer_regress'), include_deferred=True), key=lambda obj: obj._meta.object_name) 145 [<class 'regressiontests.defer_regress.models.Child'>, <class 'regressiontests.defer_regress.models.Item'>, <class 'regressiontests.defer_regress.models.Item_Deferred_name'>, <class 'regressiontests.defer_regress.models.Item_Deferred_name_other_value_text'>, <class 'regressiontests.defer_regress.models.Item_Deferred_other_value_text_value'>, <class 'regressiontests.defer_regress.models.Item_Deferred_text_value'>, <class 'regressiontests.defer_regress.models.Leaf'>, <class 'regressiontests.defer_regress.models.Leaf_Deferred_name_value'>, <class 'regressiontests.defer_regress.models.Leaf_Deferred_second_child_value'>, <class 'regressiontests.defer_regress.models.Leaf_Deferred_value'>, <class 'regressiontests.defer_regress.models.RelatedItem'>, <class 'regressiontests.defer_regress.models.RelatedItem_Deferred_item_id'>, <class 'regressiontests.defer_regress.models.ResolveThis'>, <class 'regressiontests.defer_regress.models.ResolveThis_Deferred_num'>] 146 145 [<class 'regressiontests.defer_regress.models.Child'>, <class 'regressiontests.defer_regress.models.Item'>, <class 'regressiontests.defer_regress.models.Item_Deferred_name'>, <class 'regressiontests.defer_regress.models.Item_Deferred_name_other_value_text'>, <class 'regressiontests.defer_regress.models.Item_Deferred_name_other_value_value'>, <class 'regressiontests.defer_regress.models.Item_Deferred_other_value_text_value'>, <class 'regressiontests.defer_regress.models.Item_Deferred_text_value'>, <class 'regressiontests.defer_regress.models.Leaf'>, <class 'regressiontests.defer_regress.models.Leaf_Deferred_child_id_second_child_id_value'>, <class 'regressiontests.defer_regress.models.Leaf_Deferred_name_value'>, <class 'regressiontests.defer_regress.models.Leaf_Deferred_second_child_value'>, <class 'regressiontests.defer_regress.models.Leaf_Deferred_value'>, <class 'regressiontests.defer_regress.models.RelatedItem'>, <class 'regressiontests.defer_regress.models.RelatedItem_Deferred_'>, <class 'regressiontests.defer_regress.models.RelatedItem_Deferred_item_id'>, <class 'regressiontests.defer_regress.models.ResolveThis'>, <class 'regressiontests.defer_regress.models.ResolveThis_Deferred_num'>] 147 146 """ 148 147 } 149 148