Ticket #17: patch

File patch, 4.0 KB (added by (removed), 8 years ago)

rough stab at instance caching

  • django/db/models/base.py

    === modified file 'django/db/models/base.py'
     
    1414from django.utils.functional import curry
    1515from django.conf import settings
    1616from itertools import izip
     17from weakref import WeakValueDictionary
    1718import types
    1819import sys
    1920import os
     
    7172        # registered version.
    7273        return get_model(new_class._meta.app_label, name, False)
    7374
     75    def __call__(cls, *args, **kwargs):
     76        if cls._meta.has_auto_field:
     77            key = cls._get_cache_key(args, kwargs)
     78            if key is not None:
     79                obj = cls.__instance_cache__.get(key)
     80                if obj is None:
     81                    obj = super(ModelBase, cls).__call__(*args, **kwargs)
     82                    cls.__instance_cache__[key] = obj
     83            else:
     84                obj = super(ModelBase, cls).__call__(*args, **kwargs)
     85        else:
     86            obj = super(ModelBase, cls).__call__(*args, **kwargs)
     87        return obj
     88
     89
    7490class Model(object):
    7591    __metaclass__ = ModelBase
    7692
     
    89105    def __ne__(self, other):
    90106        return not self.__eq__(other)
    91107
     108    def _get_cache_key(cls, args, kwargs):
     109        # this should be calculated *once*, but isn't atm
     110        pk_position = cls._meta.fields.index(cls._meta.pk)
     111        if len(args) > pk_position:
     112            return args[pk_position]
     113        pk = cls._meta.pk
     114        if pk.name in kwargs:
     115            return kwargs[pk.name]
     116        elif pk.attname in kwargs:
     117            return kwargs[pk.attname]
     118        return None
     119    _get_cache_key = classmethod(_get_cache_key)
     120
     121    def get_cached_instance(cls, id):
     122        return cls.__instance_cache__.get(id)
     123    get_cached_instance = classmethod(get_cached_instance)
     124
    92125    def __init__(self, *args, **kwargs):
    93126        dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs)
    94127        # there is a rather weird disparity here; if kwargs, it's set, then args overrides it.
     
    185218        if hasattr(cls, 'get_absolute_url'):
    186219            cls.get_absolute_url = curry(get_absolute_url, opts, cls.get_absolute_url)
    187220
     221        cls.__instance_cache__ = WeakValueDictionary()
     222
    188223        dispatcher.send(signal=signals.class_prepared, sender=cls)
    189224
    190225    _prepare = classmethod(_prepare)
     
    241276                setattr(self, self._meta.pk.attname, backend.get_last_insert_id(cursor, self._meta.db_table, self._meta.pk.column))
    242277        transaction.commit_unless_managed()
    243278
     279        # if we're a new instance that hasn't been written in; save ourself.
     280        if self._meta.has_auto_field:
     281            self.__instance_cache__.setdefault(pk_val, self)
     282
    244283        # Run any post-save hooks.
    245284        dispatcher.send(signal=signals.post_save, sender=self.__class__, instance=self)
    246285
  • django/db/models/fields/related.py

    === modified file 'django/db/models/fields/related.py'
     
    163163                if self.field.null:
    164164                    return None
    165165                raise self.field.rel.to.DoesNotExist
    166             other_field = self.field.rel.get_related_field()
    167             if other_field.rel:
    168                 params = {'%s__pk' % self.field.rel.field_name: val}
    169             else:
    170                 params = {'%s__exact' % self.field.rel.field_name: val}
    171             rel_obj = self.field.rel.to._default_manager.get(**params)
     166            rel_obj = self.field.rel.to.get_cached_instance(val)
     167            if rel_obj is None:
     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)
    172174            setattr(instance, cache_name, rel_obj)
    173175            return rel_obj
    174176
Back to Top