Django

Code

Ticket #7338: method_cache.diff

File method_cache.diff, 7.7 kB (added by marinho, 2 years ago)

Updated patch with cache method

  • django/db/models/sql/query.py

    old new  
    2121from django.core.exceptions import FieldError 
    2222from datastructures import EmptyResultSet, Empty, MultiJoin 
    2323from constants import * 
     24from django.core.cache import cache 
    2425 
    2526try: 
    2627    set 
     
    202203                fields = self.select_fields + self.related_select_fields 
    203204            else: 
    204205                fields = self.model._meta.fields 
    205         for rows in self.execute_sql(MULTI): 
     206 
     207        if getattr(self, 'cache_timeout', None): 
     208            """ 
     209            Check cache for stored objects from an exactly equal query 
     210            """ 
     211            k = str(self) 
     212 
     213            try: 
     214                import hashlib 
     215            except ImportError: 
     216                import sha 
     217                k = sha.new(k).hexdigest() 
     218            else: 
     219                k = hashlib.sha1(k).hexdigest() 
     220 
     221            if cache.has_key(k) and cache.get(k): 
     222                sql_result = cache.get(k, []) 
     223            else: 
     224                cache.set(k, [i for i in self.execute_sql(MULTI)], self.cache_timeout) 
     225                sql_result = cache.get(k, []) 
     226        else: 
     227            sql_result = self.execute_sql(MULTI) 
     228 
     229        for rows in sql_result: 
    206230            for row in rows: 
    207231                if resolve_columns: 
    208232                    row = self.resolve_columns(row, fields) 
  • django/db/models/manager.py

    old new  
    123123    def reverse(self, *args, **kwargs): 
    124124        return self.get_query_set().reverse(*args, **kwargs) 
    125125 
     126    def cache(self, timeout=20): 
     127        return self.get_query_set().cache(timeout=timeout) 
     128         
    126129    def _insert(self, values, **kwargs): 
    127130        return insert_query(self.model, values, **kwargs) 
    128131 
  • django/db/models/query.py

    old new  
    614614        """ 
    615615        pass 
    616616 
     617    def cache(self, timeout=20): 
     618        """ 
     619        Forces the current queryset to check if a exact equal query has been 
     620        stored in the cache. The expiration time is the seconds in 'timeout' 
     621        variable 
     622        """ 
     623        self.query.cache_timeout = timeout 
    617624 
     625        return self 
     626 
     627 
    618628class ValuesQuerySet(QuerySet): 
    619629    def __init__(self, *args, **kwargs): 
    620630        super(ValuesQuerySet, self).__init__(*args, **kwargs) 
  • tests/modeltests/queryset_cache/models.py

    old new  
     1""" 
     240. Storing queryset results in the cache 
     3 
     4Stores objects got with a queryset to the cache, modify one of those, 
     5get objects again, check if thei has been stored correctly. 
     6 
     7The porpose of this function is avoid identical queries done to the 
     8database in a short time, when possible. 
     9""" 
     10from datetime import datetime 
     11 
     12from django.db import models 
     13 
     14class Entry(models.Model): 
     15    title = models.CharField(max_length=100) 
     16    body = models.TextField(blank=True) 
     17    pub_date = models.DateTimeField(default=datetime.now) 
     18 
     19    def __unicode__(self): 
     20        return self.title 
     21 
     22    class Meta: 
     23        ordering = ('id',) 
     24 
     25__test__ = {'API_TESTS':""" 
     26 
     27# Tests if cache engine its working 
     28>>> from django.core.cache import cache 
     29>>> cache.set('name_of_key', 'Tarsila') 
     30>>> cache.get('name_of_key') == 'Tarsila' 
     31True 
     32 
     33# Create a couple of Entries. 
     34>>> e1 = Entry.objects.create(title='My first', body='The one') 
     35>>> e2 = Entry.objects.create(title='My second', body='The two') 
     36>>> e3 = Entry.objects.create(title='My third', body='The three') 
     37>>> e4 = Entry.objects.create(title='My forth', body='The four') 
     38 
     39# Run a non-cached query 
     40>>> Entry.objects.all() 
     41[<Entry: My first>, <Entry: My second>, <Entry: My third>, <Entry: My forth>] 
     42 
     43# Modify one 
     44>>> e1.title = 'The first'; e1.save() 
     45 
     46# Run a non-cached query again 
     47>>> Entry.objects.all() 
     48[<Entry: The first>, <Entry: My second>, <Entry: My third>, <Entry: My forth>] 
     49 
     50# Run a cached query 
     51>>> Entry.objects.cache(120) 
     52[<Entry: The first>, <Entry: My second>, <Entry: My third>, <Entry: My forth>] 
     53 
     54# Modify one 
     55>>> e1.title = 'My first'; e1.save() 
     56 
     57# Run a cached query again (not changed) 
     58>>> Entry.objects.cache(120) 
     59[<Entry: The first>, <Entry: My second>, <Entry: My third>, <Entry: My forth>] 
     60 
     61# Run a non-cached query (changed) 
     62>>> Entry.objects.all() 
     63[<Entry: My first>, <Entry: My second>, <Entry: My third>, <Entry: My forth>] 
     64"""} 
  • docs/db-api.txt

    old new  
    10711071``extra()`` is new. Previously, you could attempt to pass parameters for 
    10721072``select`` in the ``params`` argument, but it worked very unreliably. 
    10731073 
     1074``cache(timeout=20)`` 
     1075~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     1076 
     1077**New in Django development version** 
     1078 
     1079Use the ``cache()`` method to store the queryset's elements to the cache, for the expiration time 
     1080defined by the optional argument ``timeout`` (in seconds). 
     1081 
     1082Examples:: 
     1083 
     1084    >>> Entry.objects.cache(300) 
     1085    [<Entry: Beyond the database>] 
     1086 
     1087The example above evaluates to this SQL: 
     1088 
     1089    SELECT 
     1090      "diario_entry"."id", "diario_entry"."title", "diario_entry"."slug", 
     1091      "diario_entry"."body_source", "diario_entry"."body", "diario_entry"."markup", 
     1092      "diario_entry"."is_draft", "diario_entry"."pub_date", "diario_entry"."tags", 
     1093      "diario_entry"."content_type_id", "diario_entry"."object_id" 
     1094    FROM "diario_entry" 
     1095    ORDER BY "diario_entry"."pub_date" DESC 
     1096 
     1097When using the method ``cache()``, before request the results for this query from the database the 
     1098ORM will generate a hash code for this SQL and will check in the cache for an item with the same 
     1099hash code, what means that if an identical query has been done before, it will be stored in memory 
     1100and will return with on request to database server. 
     1101 
     1102The expiration time (``timeout`` argument) defines how many seconds the cache engine will handle the 
     1103objects. 
     1104 
     1105You can also define that all queries from a model class are stored in the cache, like the example 
     1106below:: 
     1107 
     1108    class EntryManager(models.Manager): 
     1109        def get_query_set(self): 
     1110            q = super(EntryManager, self).get_query_set() 
     1111     
     1112            return q.cache(120) 
     1113 
     1114This will make all queryset from ``Entry`` model class be made with the ``cache()`` method. 
     1115 
     1116**Important observations**:: 
     1117 
     1118    * You have to keep in your mind that cached objects are not the best way for all cases, because 
     1119    sometimes you need to get results exactly as they are in database. E.g: in the admin site. Be 
     1120    careful when using this method, you can have problems getting old values thinking that the ORM 
     1121    is crazy; 
     1122 
     1123    * The usage of this method makes sense only with memory based cache engines (``memcached`` and 
     1124    ``locmem``); 
     1125 
     1126    * The main function of this method is increase the scalability of your querysets. The logic 
     1127    sense of this method is: more concurrent users you have, less queries to the database. 
     1128 
    10741129QuerySet methods that do not return QuerySets 
    10751130--------------------------------------------- 
    10761131