=== modified file 'django/db/models/base.py' --- django/db/models/base.py 2007-02-08 05:26:44 +0000 +++ django/db/models/base.py 2007-02-09 20:04:27 +0000 @@ -14,6 +14,7 @@ from django.utils.functional import curry from django.conf import settings from itertools import izip +from weakref import WeakValueDictionary import types import sys import os @@ -71,6 +72,21 @@ # registered version. return get_model(new_class._meta.app_label, name, False) + def __call__(cls, *args, **kwargs): + if cls._meta.has_auto_field: + key = cls._get_cache_key(args, kwargs) + if key is not None: + obj = cls.__instance_cache__.get(key) + if obj is None: + obj = super(ModelBase, cls).__call__(*args, **kwargs) + cls.__instance_cache__[key] = obj + else: + obj = super(ModelBase, cls).__call__(*args, **kwargs) + else: + obj = super(ModelBase, cls).__call__(*args, **kwargs) + return obj + + class Model(object): __metaclass__ = ModelBase @@ -89,6 +105,23 @@ def __ne__(self, other): return not self.__eq__(other) + def _get_cache_key(cls, args, kwargs): + # this should be calculated *once*, but isn't atm + pk_position = cls._meta.fields.index(cls._meta.pk) + if len(args) > pk_position: + return args[pk_position] + pk = cls._meta.pk + if pk.name in kwargs: + return kwargs[pk.name] + elif pk.attname in kwargs: + return kwargs[pk.attname] + return None + _get_cache_key = classmethod(_get_cache_key) + + def get_cached_instance(cls, id): + return cls.__instance_cache__.get(id) + get_cached_instance = classmethod(get_cached_instance) + def __init__(self, *args, **kwargs): dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs) # there is a rather weird disparity here; if kwargs, it's set, then args overrides it. @@ -185,6 +218,8 @@ if hasattr(cls, 'get_absolute_url'): cls.get_absolute_url = curry(get_absolute_url, opts, cls.get_absolute_url) + cls.__instance_cache__ = WeakValueDictionary() + dispatcher.send(signal=signals.class_prepared, sender=cls) _prepare = classmethod(_prepare) @@ -241,6 +276,10 @@ setattr(self, self._meta.pk.attname, backend.get_last_insert_id(cursor, self._meta.db_table, self._meta.pk.column)) transaction.commit_unless_managed() + # if we're a new instance that hasn't been written in; save ourself. + if self._meta.has_auto_field: + self.__instance_cache__.setdefault(pk_val, self) + # Run any post-save hooks. dispatcher.send(signal=signals.post_save, sender=self.__class__, instance=self) === modified file 'django/db/models/fields/related.py' --- django/db/models/fields/related.py 2007-02-04 21:23:07 +0000 +++ django/db/models/fields/related.py 2007-02-09 11:52:52 +0000 @@ -163,12 +163,14 @@ if self.field.null: return None raise self.field.rel.to.DoesNotExist - other_field = self.field.rel.get_related_field() - if other_field.rel: - params = {'%s__pk' % self.field.rel.field_name: val} - else: - params = {'%s__exact' % self.field.rel.field_name: val} - rel_obj = self.field.rel.to._default_manager.get(**params) + rel_obj = self.field.rel.to.get_cached_instance(val) + if rel_obj is None: + other_field = self.field.rel.get_related_field() + if other_field.rel: + params = {'%s__pk' % self.field.rel.field_name: val} + else: + params = {'%s__exact' % self.field.rel.field_name: val} + rel_obj = self.field.rel.to._default_manager.get(**params) setattr(instance, cache_name, rel_obj) return rel_obj