<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://wow.curse.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Curse Development : python</title><link>http://wow.curse.com/blogs/curse-development-en-users/archive/tags/python/default.aspx</link><description>Tags: python</description><dc:language>en-US</dc:language><generator>CommunityServer 2008 SP1 (Build: 30619.63)</generator><item><title>Django CacheManager</title><link>http://wow.curse.com/blogs/curse-development-en-users/archive/2008/09/19/N38Id.aspx</link><pubDate>Thu, 05 Jul 2007 11:27:04 GMT</pubDate><guid isPermaLink="false">045f8e2a-3b25-43b2-9769-9c60de2974e3:258338</guid><dc:creator>Zinor</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://wow.curse.com/blogs/curse-development-en-users/rsscomments.aspx?PostID=258338</wfw:commentRss><comments>http://wow.curse.com/blogs/curse-development-en-users/archive/2008/09/19/N38Id.aspx#comments</comments><description>&lt;p&gt;We have been working on some optimizations on the backend lately, and one thing discussed was a new approach at handling caching.
&lt;/p&gt;&lt;p&gt;Django offers several, none of which satisfy what a heavy database site needs, and calling cache.get() everywhere is just tiresome, and ends up with data duplication.
&lt;/p&gt;&lt;p&gt;Today we came up with our tentative alternative, CacheManager.
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span style="color:#007020;font-weight:bold;"&gt;from&lt;/span&gt; &lt;span style="color:#0e84b5;font-weight:bold;"&gt;django.db.models.manager&lt;/span&gt; &lt;span style="color:#007020;font-weight:bold;"&gt;import&lt;/span&gt; Manager
&lt;span style="color:#007020;font-weight:bold;"&gt;from&lt;/span&gt; &lt;span style="color:#0e84b5;font-weight:bold;"&gt;django.db.models.query&lt;/span&gt; &lt;span style="color:#007020;font-weight:bold;"&gt;import&lt;/span&gt; QuerySet
&lt;span style="color:#007020;font-weight:bold;"&gt;from&lt;/span&gt; &lt;span style="color:#0e84b5;font-weight:bold;"&gt;django.core.cache&lt;/span&gt; &lt;span style="color:#007020;font-weight:bold;"&gt;import&lt;/span&gt; cache

DEFAULT_CACHE_TIME &lt;span style="color:#666666;"&gt;=&lt;/span&gt; &lt;span style="color:#40a070;"&gt;15&lt;/span&gt;&lt;span style="color:#666666;"&gt;*&lt;/span&gt;&lt;span style="color:#40a070;"&gt;60&lt;/span&gt; &lt;span style="color:#60a0b0;font-style:italic;"&gt;# 15 minutes&lt;/span&gt;
&lt;span style="color:#60a0b0;font-style:italic;"&gt;# TODO&lt;/span&gt;
&lt;span style="color:#60a0b0;font-style:italic;"&gt;# - Come up with a better method for invalidation&lt;/span&gt;
&lt;span style="color:#60a0b0;font-style:italic;"&gt;# - Add invalidation for count() when a queryset is invalidated&lt;/span&gt;
&lt;span style="color:#60a0b0;font-style:italic;"&gt;# - Find a way to make AutoCacheManager override `objects` in models&lt;/span&gt;
&lt;span style="color:#60a0b0;font-style:italic;"&gt;# - Add some handling to allow CacheManager to react differently based on query type (get, count, filter, select_related)&lt;/span&gt;

&lt;span style="color:#60a0b0;font-style:italic;"&gt;# CacheManager -- A manager to store and retrieve cached objects using CACHE_BACKEND&lt;/span&gt;
&lt;span style="color:#60a0b0;font-style:italic;"&gt;# (Optional) &amp;lt;string key_prefix&amp;gt; -- the key prefix for all cached objects on this model [default: db_table]&lt;/span&gt;
&lt;span style="color:#60a0b0;font-style:italic;"&gt;# (Optional) &amp;lt;int timeout&amp;gt; -- in seconds, the maximum time before data is invalidated&lt;/span&gt;

&lt;span style="color:#60a0b0;font-style:italic;"&gt;# cachemanager.clean() -- Invalidates cached data&lt;/span&gt;
&lt;span style="color:#60a0b0;font-style:italic;"&gt;# &amp;lt;instance/queryset data&amp;gt; -- the queryset, or instance of the object to be invalidated&lt;/span&gt;
&lt;span style="color:#007020;font-weight:bold;"&gt;class&lt;/span&gt; &lt;span style="color:#0e84b5;font-weight:bold;"&gt;CacheManager&lt;/span&gt;(Manager):
&lt;span style="color:#007020;font-weight:bold;"&gt;def&lt;/span&gt; &lt;span style="color:#06287e;"&gt;__init__&lt;/span&gt;(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;, &lt;span style="color:#666666;"&gt;*&lt;/span&gt;args, &lt;span style="color:#666666;"&gt;**&lt;/span&gt;kwargs):
&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;key_prefix &lt;span style="color:#666666;"&gt;=&lt;/span&gt; kwargs&lt;span style="color:#666666;"&gt;.&lt;/span&gt;pop(&lt;span style="color:#4070a0;"&gt;&amp;#39;key_prefix&amp;#39;&lt;/span&gt;, &lt;span style="color:#007020;"&gt;None&lt;/span&gt;)
&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;timeout &lt;span style="color:#666666;"&gt;=&lt;/span&gt; kwargs&lt;span style="color:#666666;"&gt;.&lt;/span&gt;pop(&lt;span style="color:#4070a0;"&gt;&amp;#39;timeout&amp;#39;&lt;/span&gt;, &lt;span style="color:#007020;"&gt;None&lt;/span&gt;)
Manager&lt;span style="color:#666666;"&gt;.&lt;/span&gt;__init__(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;)

&lt;span style="color:#007020;font-weight:bold;"&gt;def&lt;/span&gt; &lt;span style="color:#06287e;"&gt;get_query_set&lt;/span&gt;(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;):
&lt;span style="color:#007020;font-weight:bold;"&gt;return&lt;/span&gt; CachedQuerySet(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;model, &lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;timeout, &lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;key_prefix)

&lt;span style="color:#60a0b0;font-style:italic;"&gt;# clean will accept either a queryset or an instance&lt;/span&gt;
&lt;span style="color:#007020;font-weight:bold;"&gt;def&lt;/span&gt; &lt;span style="color:#06287e;"&gt;clean&lt;/span&gt;(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;, data):
&lt;span style="color:#60a0b0;font-style:italic;"&gt;# invalidate the .get() request&lt;/span&gt;
&lt;span style="color:#007020;font-weight:bold;"&gt;if&lt;/span&gt; &lt;span style="color:#007020;"&gt;isinstance&lt;/span&gt;(data, &lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;model):
&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;clean(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;filter(pk&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;_get_pk_val()))
&lt;span style="color:#007020;font-weight:bold;"&gt;elif&lt;/span&gt; &lt;span style="color:#007020;"&gt;isinstance&lt;/span&gt;(data, CachedQuerySet):
&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;clean()
&lt;span style="color:#007020;font-weight:bold;"&gt;else&lt;/span&gt;:
&lt;span style="color:#007020;font-weight:bold;"&gt;raise&lt;/span&gt; &lt;span style="color:#007020;"&gt;TypeError&lt;/span&gt;(&lt;span style="color:#4070a0;"&gt;&amp;quot;instance or queryset required for data, got &lt;/span&gt;&lt;span style="color:#70a0d0;font-style:italic;"&gt;%r&lt;/span&gt;&lt;span style="color:#4070a0;"&gt;&amp;quot;&lt;/span&gt; &lt;span style="color:#666666;"&gt;%&lt;/span&gt; (data,))

&lt;span style="color:#60a0b0;font-style:italic;"&gt;# CachedQuerySet -- Extends the QuerySet object -- additionally adds a .cache() method&lt;/span&gt;

&lt;span style="color:#60a0b0;font-style:italic;"&gt;# queryset.cache() -- Overrides CacheManager&amp;#39;s options for this QuerySet&lt;/span&gt;
&lt;span style="color:#60a0b0;font-style:italic;"&gt;# (Optional) &amp;lt;string key_prefix&amp;gt; -- the key prefix for all cached objects on this model [default: db_table]&lt;/span&gt;
&lt;span style="color:#60a0b0;font-style:italic;"&gt;# (Optional) &amp;lt;int timeout&amp;gt; -- in seconds, the maximum time before data is invalidated&lt;/span&gt;

&lt;span style="color:#60a0b0;font-style:italic;"&gt;# queryset.clean() -- Removes queryset from the cache -- recommended to use cachemanager.clean()&lt;/span&gt;
&lt;span style="color:#60a0b0;font-style:italic;"&gt;# must be called as the last method of the queryset&lt;/span&gt;
&lt;span style="color:#60a0b0;font-style:italic;"&gt;# &amp;lt;instance/queryset data&amp;gt; -- the queryset, or instance of the object to be invalidated&lt;/span&gt;
&lt;span style="color:#007020;font-weight:bold;"&gt;class&lt;/span&gt; &lt;span style="color:#0e84b5;font-weight:bold;"&gt;CachedQuerySet&lt;/span&gt;(QuerySet):
&lt;span style="color:#007020;font-weight:bold;"&gt;def&lt;/span&gt; &lt;span style="color:#06287e;"&gt;__init__&lt;/span&gt;(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;, model&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#007020;"&gt;None&lt;/span&gt;, &lt;span style="color:#666666;"&gt;*&lt;/span&gt;args, &lt;span style="color:#666666;"&gt;**&lt;/span&gt;kwargs):
&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;__cache_key &lt;span style="color:#666666;"&gt;=&lt;/span&gt; &lt;span style="color:#007020;"&gt;None&lt;/span&gt;
&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;key_prefix &lt;span style="color:#666666;"&gt;=&lt;/span&gt; kwargs&lt;span style="color:#666666;"&gt;.&lt;/span&gt;pop(&lt;span style="color:#4070a0;"&gt;&amp;#39;key_prefix&amp;#39;&lt;/span&gt;, model &lt;span style="color:#007020;font-weight:bold;"&gt;and&lt;/span&gt; model&lt;span style="color:#666666;"&gt;.&lt;/span&gt;_meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;db_table &lt;span style="color:#007020;font-weight:bold;"&gt;or&lt;/span&gt; &lt;span style="color:#4070a0;"&gt;&amp;#39;&amp;#39;&lt;/span&gt;)
&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;timeout &lt;span style="color:#666666;"&gt;=&lt;/span&gt; kwargs&lt;span style="color:#666666;"&gt;.&lt;/span&gt;pop(&lt;span style="color:#4070a0;"&gt;&amp;#39;timeout&amp;#39;&lt;/span&gt;, &lt;span style="color:#007020;"&gt;getattr&lt;/span&gt;(cache, &lt;span style="color:#4070a0;"&gt;&amp;#39;default_timeout&amp;#39;&lt;/span&gt;, DEFAULT_CACHE_TIME))
&lt;span style="color:#007020;font-weight:bold;"&gt;if&lt;/span&gt; &lt;span style="color:#007020;font-weight:bold;"&gt;not&lt;/span&gt; &lt;span style="color:#007020;"&gt;isinstance&lt;/span&gt;(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;key_prefix, &lt;span style="color:#007020;"&gt;basestring&lt;/span&gt;):
&lt;span style="color:#007020;font-weight:bold;"&gt;raise&lt;/span&gt; &lt;span style="color:#007020;"&gt;TypeError&lt;/span&gt;(&lt;span style="color:#4070a0;"&gt;&amp;quot;string required for key_prefix, got &lt;/span&gt;&lt;span style="color:#70a0d0;font-style:italic;"&gt;%r&lt;/span&gt;&lt;span style="color:#4070a0;"&gt;&amp;quot;&lt;/span&gt; &lt;span style="color:#666666;"&gt;%&lt;/span&gt; (&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;key_prefix,))
&lt;span style="color:#007020;font-weight:bold;"&gt;if&lt;/span&gt; &lt;span style="color:#007020;font-weight:bold;"&gt;not&lt;/span&gt; &lt;span style="color:#007020;"&gt;isinstance&lt;/span&gt;(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;timeout, &lt;span style="color:#007020;"&gt;int&lt;/span&gt;):
&lt;span style="color:#007020;font-weight:bold;"&gt;raise&lt;/span&gt; &lt;span style="color:#007020;"&gt;TypeError&lt;/span&gt;(&lt;span style="color:#4070a0;"&gt;&amp;quot;integer required for timeout, got &lt;/span&gt;&lt;span style="color:#70a0d0;font-style:italic;"&gt;%r&lt;/span&gt;&lt;span style="color:#4070a0;"&gt;&amp;quot;&lt;/span&gt; &lt;span style="color:#666666;"&gt;%&lt;/span&gt; (&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;timeout,))
QuerySet&lt;span style="color:#666666;"&gt;.&lt;/span&gt;__init__(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;, model)

&lt;span style="color:#007020;font-weight:bold;"&gt;def&lt;/span&gt; &lt;span style="color:#06287e;"&gt;_get_sorted_clause_key&lt;/span&gt;(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;):
&lt;span style="color:#007020;font-weight:bold;"&gt;return&lt;/span&gt; (&lt;span style="color:#007020;"&gt;isinstance&lt;/span&gt;(i, &lt;span style="color:#007020;"&gt;basestring&lt;/span&gt;) &lt;span style="color:#007020;font-weight:bold;"&gt;and&lt;/span&gt; i&lt;span style="color:#666666;"&gt;.&lt;/span&gt;lower()&lt;span style="color:#666666;"&gt;.&lt;/span&gt;replace(&lt;span style="color:#4070a0;"&gt;&amp;#39;`&amp;#39;&lt;/span&gt;, &lt;span style="color:#4070a0;"&gt;&amp;#39;&amp;#39;&lt;/span&gt;)&lt;span style="color:#666666;"&gt;.&lt;/span&gt;replace(&lt;span style="color:#4070a0;"&gt;&amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;, &lt;span style="color:#4070a0;"&gt;&amp;#39;&amp;#39;&lt;/span&gt;) &lt;span style="color:#007020;font-weight:bold;"&gt;or&lt;/span&gt; &lt;span style="color:#007020;"&gt;str&lt;/span&gt;(&lt;span style="color:#007020;"&gt;tuple&lt;/span&gt;(sorted(i))) &lt;span style="color:#007020;font-weight:bold;"&gt;for&lt;/span&gt; i &lt;span style="color:#007020;font-weight:bold;"&gt;in&lt;/span&gt; &lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;_get_sql_clause())

&lt;span style="color:#007020;font-weight:bold;"&gt;def&lt;/span&gt; &lt;span style="color:#06287e;"&gt;_get_cache_key&lt;/span&gt;(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;, xtra&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#4070a0;"&gt;&amp;#39;&amp;#39;&lt;/span&gt;):
&lt;span style="color:#007020;font-weight:bold;"&gt;if&lt;/span&gt; &lt;span style="color:#007020;font-weight:bold;"&gt;not&lt;/span&gt; &lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;__cache_key:
&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;__cache_key &lt;span style="color:#666666;"&gt;=&lt;/span&gt; &lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;key_prefix &lt;span style="color:#666666;"&gt;+&lt;/span&gt; &lt;span style="color:#007020;"&gt;str&lt;/span&gt;(&lt;span style="color:#007020;"&gt;hash&lt;/span&gt;(&lt;span style="color:#4070a0;"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;join(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;_get_sorted_clause_key()))) &lt;span style="color:#666666;"&gt;+&lt;/span&gt; xtra
&lt;span style="color:#007020;font-weight:bold;"&gt;return&lt;/span&gt; &lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;__cache_key

&lt;span style="color:#007020;font-weight:bold;"&gt;def&lt;/span&gt; &lt;span style="color:#06287e;"&gt;_get_data&lt;/span&gt;(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;):
data &lt;span style="color:#666666;"&gt;=&lt;/span&gt; cache&lt;span style="color:#666666;"&gt;.&lt;/span&gt;get(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;_get_cache_key())
&lt;span style="color:#007020;font-weight:bold;"&gt;if&lt;/span&gt; data &lt;span style="color:#007020;font-weight:bold;"&gt;is&lt;/span&gt; &lt;span style="color:#007020;"&gt;None&lt;/span&gt;:
data &lt;span style="color:#666666;"&gt;=&lt;/span&gt; QuerySet&lt;span style="color:#666666;"&gt;.&lt;/span&gt;_get_data(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;)
cache&lt;span style="color:#666666;"&gt;.&lt;/span&gt;set(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;_get_cache_key(), [d &lt;span style="color:#007020;font-weight:bold;"&gt;for&lt;/span&gt; d &lt;span style="color:#007020;font-weight:bold;"&gt;in&lt;/span&gt; data], &lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;timeout)
&lt;span style="color:#007020;font-weight:bold;"&gt;return&lt;/span&gt; data

&lt;span style="color:#007020;font-weight:bold;"&gt;def&lt;/span&gt; &lt;span style="color:#06287e;"&gt;count&lt;/span&gt;(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;):
count &lt;span style="color:#666666;"&gt;=&lt;/span&gt; cache&lt;span style="color:#666666;"&gt;.&lt;/span&gt;get(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;_get_cache_key(&lt;span style="color:#4070a0;"&gt;&amp;#39;count&amp;#39;&lt;/span&gt;))
&lt;span style="color:#007020;font-weight:bold;"&gt;if&lt;/span&gt; count &lt;span style="color:#007020;font-weight:bold;"&gt;is&lt;/span&gt; &lt;span style="color:#007020;"&gt;None&lt;/span&gt;:
count &lt;span style="color:#666666;"&gt;=&lt;/span&gt; &lt;span style="color:#007020;"&gt;int&lt;/span&gt;(QuerySet&lt;span style="color:#666666;"&gt;.&lt;/span&gt;count(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;))
cache&lt;span style="color:#666666;"&gt;.&lt;/span&gt;set(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;_get_cache_key(&lt;span style="color:#4070a0;"&gt;&amp;#39;count&amp;#39;&lt;/span&gt;), count, &lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;timeout)
&lt;span style="color:#007020;font-weight:bold;"&gt;return&lt;/span&gt; count

&lt;span style="color:#007020;font-weight:bold;"&gt;def&lt;/span&gt; &lt;span style="color:#06287e;"&gt;cache&lt;/span&gt;(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;, &lt;span style="color:#666666;"&gt;*&lt;/span&gt;args, &lt;span style="color:#666666;"&gt;**&lt;/span&gt;kwargs):
&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;key_prefix &lt;span style="color:#666666;"&gt;=&lt;/span&gt; kwargs&lt;span style="color:#666666;"&gt;.&lt;/span&gt;pop(&lt;span style="color:#4070a0;"&gt;&amp;#39;key_prefix&amp;#39;&lt;/span&gt;, &lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;key_prefix)
&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;timeout &lt;span style="color:#666666;"&gt;=&lt;/span&gt; kwargs&lt;span style="color:#666666;"&gt;.&lt;/span&gt;pop(&lt;span style="color:#4070a0;"&gt;&amp;#39;timeout&amp;#39;&lt;/span&gt;, &lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;timeout)
&lt;span style="color:#007020;font-weight:bold;"&gt;if&lt;/span&gt; &lt;span style="color:#007020;font-weight:bold;"&gt;not&lt;/span&gt; &lt;span style="color:#007020;"&gt;isinstance&lt;/span&gt;(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;key_prefix, &lt;span style="color:#007020;"&gt;basestring&lt;/span&gt;):
&lt;span style="color:#007020;font-weight:bold;"&gt;raise&lt;/span&gt; &lt;span style="color:#007020;"&gt;TypeError&lt;/span&gt;(&lt;span style="color:#4070a0;"&gt;&amp;quot;string required for key_prefix, got &lt;/span&gt;&lt;span style="color:#70a0d0;font-style:italic;"&gt;%r&lt;/span&gt;&lt;span style="color:#4070a0;"&gt;&amp;quot;&lt;/span&gt; &lt;span style="color:#666666;"&gt;%&lt;/span&gt; (&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;key_prefix,))
&lt;span style="color:#007020;font-weight:bold;"&gt;if&lt;/span&gt; &lt;span style="color:#007020;font-weight:bold;"&gt;not&lt;/span&gt; &lt;span style="color:#007020;"&gt;isinstance&lt;/span&gt;(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;timeout, &lt;span style="color:#007020;"&gt;int&lt;/span&gt;):
&lt;span style="color:#007020;font-weight:bold;"&gt;raise&lt;/span&gt; &lt;span style="color:#007020;"&gt;TypeError&lt;/span&gt;(&lt;span style="color:#4070a0;"&gt;&amp;quot;integer required for timeout, got &lt;/span&gt;&lt;span style="color:#70a0d0;font-style:italic;"&gt;%r&lt;/span&gt;&lt;span style="color:#4070a0;"&gt;&amp;quot;&lt;/span&gt; &lt;span style="color:#666666;"&gt;%&lt;/span&gt; (&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;timeout,))

&lt;span style="color:#007020;font-weight:bold;"&gt;def&lt;/span&gt; &lt;span style="color:#06287e;"&gt;clean&lt;/span&gt;(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;):
cache&lt;span style="color:#666666;"&gt;.&lt;/span&gt;delete(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;_get_cache_key())

&lt;span style="color:#60a0b0;font-style:italic;"&gt;# AutoCacheManager -- automatically replaces objects with a CacheManager and&lt;/span&gt;
&lt;span style="color:#60a0b0;font-style:italic;"&gt;# overrides save/delete functions to update the cache as needed&lt;/span&gt;
&lt;span style="color:#007020;font-weight:bold;"&gt;class&lt;/span&gt; &lt;span style="color:#0e84b5;font-weight:bold;"&gt;AutoCacheManager&lt;/span&gt;(&lt;span style="color:#007020;"&gt;object&lt;/span&gt;):
&lt;span style="color:#60a0b0;font-style:italic;"&gt;# TODO: find a way to make `objects` actually set correctly&lt;/span&gt;
objects &lt;span style="color:#666666;"&gt;=&lt;/span&gt; CacheManager()
no_cache &lt;span style="color:#666666;"&gt;=&lt;/span&gt; Manager()

&lt;span style="color:#60a0b0;font-style:italic;"&gt;# TODO: know how to clean this w/o guessing for CacheManager&lt;/span&gt;
&lt;span style="color:#007020;font-weight:bold;"&gt;def&lt;/span&gt; &lt;span style="color:#06287e;"&gt;delete&lt;/span&gt;(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;, &lt;span style="color:#666666;"&gt;*&lt;/span&gt;args, &lt;span style="color:#666666;"&gt;**&lt;/span&gt;kwargs):
&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;__class__&lt;span style="color:#666666;"&gt;.&lt;/span&gt;objects&lt;span style="color:#666666;"&gt;.&lt;/span&gt;clean(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;)
Manager&lt;span style="color:#666666;"&gt;.&lt;/span&gt;delete(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;, &lt;span style="color:#666666;"&gt;*&lt;/span&gt;args, &lt;span style="color:#666666;"&gt;**&lt;/span&gt;kwargs)

&lt;span style="color:#007020;font-weight:bold;"&gt;def&lt;/span&gt; &lt;span style="color:#06287e;"&gt;save&lt;/span&gt;(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;, &lt;span style="color:#666666;"&gt;*&lt;/span&gt;args, &lt;span style="color:#666666;"&gt;**&lt;/span&gt;kwargs):
Manager&lt;span style="color:#666666;"&gt;.&lt;/span&gt;save(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;, &lt;span style="color:#666666;"&gt;*&lt;/span&gt;args, &lt;span style="color:#666666;"&gt;**&lt;/span&gt;kwargs)
&lt;span style="color:#007020;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;__class__&lt;span style="color:#666666;"&gt;.&lt;/span&gt;objects&lt;span style="color:#666666;"&gt;.&lt;/span&gt;clean(&lt;span style="color:#007020;"&gt;self&lt;/span&gt;)
&lt;/pre&gt;&lt;/div&gt;
&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://wow.curse.com/aggbug.aspx?PostID=258338" width="1" height="1"&gt;</description><category domain="http://wow.curse.com/blogs/curse-development-en-users/archive/tags/django/default.aspx">django</category><category domain="http://wow.curse.com/blogs/curse-development-en-users/archive/tags/python/default.aspx">python</category></item></channel></rss>