Ticket #17: 17_no_tests.diff
File 17_no_tests.diff, 10.8 KB (added by , 17 years ago) |
---|
-
django/db/models/base.py
15 15 from django.utils.encoding import smart_str, force_unicode, smart_unicode 16 16 from django.conf import settings 17 17 from itertools import izip 18 from weakref import WeakValueDictionary 18 19 import types 19 20 import sys 20 21 import os … … 77 78 # registered version. 78 79 return get_model(new_class._meta.app_label, name, False) 79 80 81 def __call__(cls, *args, **kwargs): 82 """ 83 this method will either create an instance (by calling the default implementation) 84 or try to retrieve one from the class-wide cache by infering the pk value from 85 args and kwargs. If instance caching is enabled for this class, the cache is 86 populated whenever possible (ie when it is possible to infer the pk value). 87 """ 88 def new_instance(): 89 return super(ModelBase, cls).__call__(*args, **kwargs) 90 91 # we always pop those settings from kwargs not to pollute the instance 92 instance_caching_enabled = kwargs.pop('meta__instance_caching', False) or cls.meta__instance_caching 93 # simplest case, just create a new instance every time 94 if not instance_caching_enabled: 95 return new_instance() 96 97 instance_key = cls._get_cache_key(args, kwargs) 98 # depending on the arguments, we might not be able to infer the PK, so in that case we create a new instance 99 if instance_key is None: 100 return new_instance() 101 102 cached_instance = cls.get_cached_instance(key) 103 if cached_instance is None: 104 cached_instance = new_instance() 105 # FIXME test cached_instance._get_pk_val() == instance_key 106 cls.cache_instance(cached_instance) 107 108 return cached_instance 109 80 110 class Model(object): 81 111 __metaclass__ = ModelBase 82 112 … … 97 127 def __ne__(self, other): 98 128 return not self.__eq__(other) 99 129 130 def _get_cache_key(cls, args, kwargs): 131 result = None 132 pk = cls._meta.pk 133 # get the index of the pk in the class fields. this should be calculated *once*, but isn't atm 134 pk_position = cls._meta.fields.index(pk) 135 # if it's in the args, we can get it easily by index 136 if len(args) > pk_position: 137 result = args[pk_position] 138 # retrieve the pk value. Note that we use attname instead of name, to handle the case where the pk is a 139 # a ForeignKey. 140 elif pk.attname in kwargs: 141 result = kwargs[pk.attname] 142 # ok we couldn't find the value, but maybe it's a FK and we can find the corresponding object instead 143 elif pk.name != pk.attname and pk.name in kwargs: 144 result = kwargs[pk.name] 145 # if the pk value happens to be a model (which can happen wich a FK), we'd rather use its own pk as the key 146 if result is not None and isinstance(result, Model): 147 result = result._get_pk_val() 148 return result 149 _get_cache_key = classmethod(_get_cache_key) 150 151 def get_cached_instance(cls, id): 152 """ 153 Method to retrieve a cached instance by pk value. Returns None when not found (which will always be the case when caching is disabled for this class). 154 """ 155 return cls.__instance_cache__.get(id) 156 get_cached_instance = classmethod(get_cached_instance) 157 158 def cache_instance(cls, instance): 159 """ 160 Method to store an instance in the cache. The instance will only be stored if 'instance.meta__instance_cache' is 'True', which means it is 161 possible to override the class-wide settings in the instance. 162 """ 163 if instance.meta__instance_cache and instance._get_pk_val() is not None: 164 cls.__instance_cache__[instance._get_pk_val()] = instance 165 cache_instance = classmethod(cache_instance) 166 167 def flush_cached_instance(cls, instance): 168 """ 169 Method to flush an instance from the cache. The instance will always be flushed from the cache, since this is most likely called from delete(). 170 We do not test the pk value because delete() does it and it will fail silently anyway. 171 """ 172 self.__instance_cache__.pop(_get_pk_val(), None) 173 100 174 def __init__(self, *args, **kwargs): 101 175 dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs) 102 176 … … 197 271 if hasattr(cls, 'get_absolute_url'): 198 272 cls.get_absolute_url = curry(get_absolute_url, opts, cls.get_absolute_url) 199 273 274 cls.__instance_cache__ = WeakValueDictionary() 275 # enable the cache according to user preferences (off by default) 276 cls.meta__instance_caching = getattr(cls, 'meta__instance_caching', False) 277 200 278 dispatcher.send(signal=signals.class_prepared, sender=cls) 201 279 202 280 _prepare = classmethod(_prepare) … … 260 338 setattr(self, self._meta.pk.attname, connection.ops.last_insert_id(cursor, self._meta.db_table, self._meta.pk.column)) 261 339 transaction.commit_unless_managed() 262 340 341 # if we're a new instance that hasn't been written in; save ourself. 342 self.__class__.cache_instance(self) 343 263 344 # Run any post-save hooks. 264 345 dispatcher.send(signal=signals.post_save, sender=self.__class__, instance=self) 265 346 … … 319 400 seen_objs = SortedDict() 320 401 self._collect_sub_objects(seen_objs) 321 402 403 # remove ourself from the cache 404 self.__class__.flush_cached_instance(self) 322 405 # Actually delete the objects 323 406 delete_objects(seen_objs) 324 407 -
django/db/models/fields/related.py
165 165 if self.field.null: 166 166 return None 167 167 raise self.field.rel.to.DoesNotExist 168 other_field = self.field.rel.get_related_field() 169 if other_field.rel: 170 params = {'%s__pk' % self.field.rel.field_name: val} 171 else: 172 params = {'%s__exact' % self.field.rel.field_name: val} 173 rel_obj = self.field.rel.to._default_manager.get(**params) 168 # try to get a cached instance, and if that fails retrieve it from the db 169 rel_obj = self.field.rel.to.get_cached_instance(val) 170 if rel_obj is None: 171 other_field = self.field.rel.get_related_field() 172 if other_field.rel: 173 params = {'%s__pk' % self.field.rel.field_name: val} 174 else: 175 params = {'%s__exact' % self.field.rel.field_name: val} 176 rel_obj = self.field.rel.to._default_manager.get(**params) 174 177 setattr(instance, cache_name, rel_obj) 175 178 return rel_obj 176 179 -
django/db/models/query.py
1134 1134 dispatcher.send(signal=signals.pre_delete, sender=cls, instance=instance) 1135 1135 1136 1136 pk_list = [pk for pk,instance in seen_objs[cls]] 1137 # we wipe the cache now; it's *possible* some form of a __get__ lookup may reintroduce an item after 1138 # the fact with the same pk (extremely unlikely) 1139 for instance in seen_objs.values(): 1140 cls.flush_cached_instance(instance) 1141 1137 1142 for related in cls._meta.get_all_related_many_to_many_objects(): 1138 1143 if not isinstance(related.field, generic.GenericRelation): 1139 1144 for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE): … … 1167 1172 for cls in ordered_classes: 1168 1173 seen_objs[cls].reverse() 1169 1174 pk_list = [pk for pk,instance in seen_objs[cls]] 1175 for instance in seen_objs.values(): 1176 cls.flush_cached_instance(instance) 1170 1177 for offset in range(0, len(pk_list), GET_ITERATOR_CHUNK_SIZE): 1171 1178 cursor.execute("DELETE FROM %s WHERE %s IN (%s)" % \ 1172 1179 (qn(cls._meta.db_table), qn(cls._meta.pk.column), -
django/core/serializers/xml_serializer.py
176 176 else: 177 177 value = field.to_python(getInnerText(field_node).strip()) 178 178 data[field.name] = value 179 179 data["meta__instance_cache"] = False 180 180 # Return a DeserializedObject so that the m2m data has a place to live. 181 181 return base.DeserializedObject(Model(**data), m2m_data) 182 182 … … 234 234 else: 235 235 pass 236 236 return u"".join(inner_text) 237 -
django/core/serializers/python.py
88 88 # Handle all other fields 89 89 else: 90 90 data[field.name] = field.to_python(field_value) 91 91 data["meta__instance_cache"] = False 92 92 yield base.DeserializedObject(Model(**data), m2m_data) 93 93 94 94 def _get_model(model_identifier): -
tests/modeltests/select_related/models.py
107 107 1 108 108 109 109 # select_related() also of course applies to entire lists, not just items. 110 # Without select_related() 110 # Without select_related() (note instance caching still reduces this from 9 to 5) 111 111 >>> db.reset_queries() 112 112 >>> world = Species.objects.all() 113 113 >>> [o.genus.family for o in world] 114 114 [<Family: Drosophilidae>, <Family: Hominidae>, <Family: Fabaceae>, <Family: Amanitacae>] 115 115 >>> len(db.connection.queries) 116 9 116 5 117 117 118 118 # With select_related(): 119 119 >>> db.reset_queries() … … 129 129 >>> pea.genus.family.order.klass.phylum.kingdom.domain 130 130 <Domain: Eukaryota> 131 131 132 # Notice: one few query than above because of depth=1132 # notice: instance caching saves the day; would be 7 without. 133 133 >>> len(db.connection.queries) 134 7 134 1 135 135 136 136 >>> db.reset_queries() 137 137 >>> pea = Species.objects.select_related(depth=5).get(name="sativum") 138 138 >>> pea.genus.family.order.klass.phylum.kingdom.domain 139 139 <Domain: Eukaryota> 140 140 >>> len(db.connection.queries) 141 3 141 1 142 142 143 143 >>> db.reset_queries() 144 144 >>> world = Species.objects.all().select_related(depth=2) 145 145 >>> [o.genus.family.order for o in world] 146 146 [<Order: Diptera>, <Order: Primates>, <Order: Fabales>, <Order: Agaricales>] 147 147 >>> len(db.connection.queries) 148 5 148 1 149 149 150 150 # Reset DEBUG to where we found it. 151 151 >>> settings.DEBUG = False