Index: django/db/models/sql/query.py
===================================================================
--- django/db/models/sql/query.py	(revisão 8070)
+++ django/db/models/sql/query.py	(cópia de trabalho)
@@ -21,6 +21,7 @@
 from django.core.exceptions import FieldError
 from datastructures import EmptyResultSet, Empty, MultiJoin
 from constants import *
+from django.core.cache import cache
 
 try:
     set
@@ -202,7 +203,30 @@
                 fields = self.select_fields + self.related_select_fields
             else:
                 fields = self.model._meta.fields
-        for rows in self.execute_sql(MULTI):
+
+        if getattr(self, 'cache_timeout', None):
+            """
+            Check cache for stored objects from an exactly equal query
+            """
+            k = str(self)
+
+            try:
+                import hashlib
+            except ImportError:
+                import sha
+                k = sha.new(k).hexdigest()
+            else:
+                k = hashlib.sha1(k).hexdigest()
+
+            if cache.has_key(k) and cache.get(k):
+                sql_result = cache.get(k, [])
+            else:
+                cache.set(k, [i for i in self.execute_sql(MULTI)], self.cache_timeout)
+                sql_result = cache.get(k, [])
+        else:
+            sql_result = self.execute_sql(MULTI)
+
+        for rows in sql_result:
             for row in rows:
                 if resolve_columns:
                     row = self.resolve_columns(row, fields)
Index: django/db/models/manager.py
===================================================================
--- django/db/models/manager.py	(revisão 8070)
+++ django/db/models/manager.py	(cópia de trabalho)
@@ -123,6 +123,9 @@
     def reverse(self, *args, **kwargs):
         return self.get_query_set().reverse(*args, **kwargs)
 
+    def cache(self, timeout=20):
+        return self.get_query_set().cache(timeout=timeout)
+        
     def _insert(self, values, **kwargs):
         return insert_query(self.model, values, **kwargs)
 
Index: django/db/models/query.py
===================================================================
--- django/db/models/query.py	(revisão 8070)
+++ django/db/models/query.py	(cópia de trabalho)
@@ -614,7 +614,17 @@
         """
         pass
 
+    def cache(self, timeout=20):
+        """
+        Forces the current queryset to check if a exact equal query has been
+        stored in the cache. The expiration time is the seconds in 'timeout'
+        variable
+        """
+        self.query.cache_timeout = timeout
 
+        return self
+
+
 class ValuesQuerySet(QuerySet):
     def __init__(self, *args, **kwargs):
         super(ValuesQuerySet, self).__init__(*args, **kwargs)
Index: tests/modeltests/queryset_cache/__init__.py
===================================================================
Index: tests/modeltests/queryset_cache/models.py
===================================================================
--- tests/modeltests/queryset_cache/models.py	(revisão 0)
+++ tests/modeltests/queryset_cache/models.py	(revisão 0)
@@ -0,0 +1,64 @@
+"""
+40. Storing queryset results in the cache
+
+Stores objects got with a queryset to the cache, modify one of those,
+get objects again, check if thei has been stored correctly.
+
+The porpose of this function is avoid identical queries done to the
+database in a short time, when possible.
+"""
+from datetime import datetime
+
+from django.db import models
+
+class Entry(models.Model):
+    title = models.CharField(max_length=100)
+    body = models.TextField(blank=True)
+    pub_date = models.DateTimeField(default=datetime.now)
+
+    def __unicode__(self):
+        return self.title
+
+    class Meta:
+        ordering = ('id',)
+
+__test__ = {'API_TESTS':"""
+
+# Tests if cache engine its working
+>>> from django.core.cache import cache
+>>> cache.set('name_of_key', 'Tarsila')
+>>> cache.get('name_of_key') == 'Tarsila'
+True
+
+# Create a couple of Entries.
+>>> e1 = Entry.objects.create(title='My first', body='The one')
+>>> e2 = Entry.objects.create(title='My second', body='The two')
+>>> e3 = Entry.objects.create(title='My third', body='The three')
+>>> e4 = Entry.objects.create(title='My forth', body='The four')
+
+# Run a non-cached query
+>>> Entry.objects.all()
+[<Entry: My first>, <Entry: My second>, <Entry: My third>, <Entry: My forth>]
+
+# Modify one
+>>> e1.title = 'The first'; e1.save()
+
+# Run a non-cached query again
+>>> Entry.objects.all()
+[<Entry: The first>, <Entry: My second>, <Entry: My third>, <Entry: My forth>]
+
+# Run a cached query
+>>> Entry.objects.cache(120)
+[<Entry: The first>, <Entry: My second>, <Entry: My third>, <Entry: My forth>]
+
+# Modify one
+>>> e1.title = 'My first'; e1.save()
+
+# Run a cached query again (not changed)
+>>> Entry.objects.cache(120)
+[<Entry: The first>, <Entry: My second>, <Entry: My third>, <Entry: My forth>]
+
+# Run a non-cached query (changed)
+>>> Entry.objects.all()
+[<Entry: My first>, <Entry: My second>, <Entry: My third>, <Entry: My forth>]
+"""}
Index: docs/db-api.txt
===================================================================
--- docs/db-api.txt	(revisão 8070)
+++ docs/db-api.txt	(cópia de trabalho)
@@ -1071,6 +1071,61 @@
 ``extra()`` is new. Previously, you could attempt to pass parameters for
 ``select`` in the ``params`` argument, but it worked very unreliably.
 
+``cache(timeout=20)``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**New in Django development version**
+
+Use the ``cache()`` method to store the queryset's elements to the cache, for the expiration time
+defined by the optional argument ``timeout`` (in seconds).
+
+Examples::
+
+    >>> Entry.objects.cache(300)
+    [<Entry: Beyond the database>]
+
+The example above evaluates to this SQL:
+
+    SELECT
+      "diario_entry"."id", "diario_entry"."title", "diario_entry"."slug",
+      "diario_entry"."body_source", "diario_entry"."body", "diario_entry"."markup",
+      "diario_entry"."is_draft", "diario_entry"."pub_date", "diario_entry"."tags",
+      "diario_entry"."content_type_id", "diario_entry"."object_id"
+    FROM "diario_entry"
+    ORDER BY "diario_entry"."pub_date" DESC
+
+When using the method ``cache()``, before request the results for this query from the database the
+ORM will generate a hash code for this SQL and will check in the cache for an item with the same
+hash code, what means that if an identical query has been done before, it will be stored in memory
+and will return with on request to database server.
+
+The expiration time (``timeout`` argument) defines how many seconds the cache engine will handle the
+objects.
+
+You can also define that all queries from a model class are stored in the cache, like the example
+below::
+
+    class EntryManager(models.Manager):
+        def get_query_set(self):
+            q = super(EntryManager, self).get_query_set()
+    
+            return q.cache(120)
+
+This will make all queryset from ``Entry`` model class be made with the ``cache()`` method.
+
+**Important observations**::
+
+    * You have to keep in your mind that cached objects are not the best way for all cases, because
+    sometimes you need to get results exactly as they are in database. E.g: in the admin site. Be
+    careful when using this method, you can have problems getting old values thinking that the ORM
+    is crazy;
+
+    * The usage of this method makes sense only with memory based cache engines (``memcached`` and
+    ``locmem``);
+
+    * The main function of this method is increase the scalability of your querysets. The logic
+    sense of this method is: more concurrent users you have, less queries to the database.
+
 QuerySet methods that do not return QuerySets
 ---------------------------------------------
 
