Code

Ticket #17: patch

File patch, 4.0 KB (added by (removed), 7 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