Ticket #7338: method_cache.diff

File method_cache.diff, 7.7 KB (added by Marinho Brandão, 16 years ago)

Updated patch with cache method

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

     
    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

     
    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

     
    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

     
     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

     
    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
Back to Top