I’m trying to cache access to the Django profile object. I’m using django-redis-cache to cache data in this project. I’m using a snippet for automatically creating a profile if one does not exist. Here is a simplified version of what I am doing (without caching):
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
Whenever profile information is needed, the user.profile property is accessed. That works as expected, however, when I try to cache the profile property, such as in Exhibit 1, I still see SQL queries (in django-debug-toolbar) that are selecting the profile and are not taking advantage of the cache.
Specifically, the cache_object_list() function from Exhibit 2 is a bit of code that checks to see if a cached value is available. If it is, it calls the cache key. If not, it runs the query passed to it (via the “query” argument) and caches the results.
cache_object_list() prints “Hit” or “Miss” indicating a cache hit or miss. After refreshing twice, everything is reported as a hit (as expected). However, django-debug-toolbar still shows no reduction in query count and shows queries selecting the profile.
Does anyone have any advice as to how to ensure that the user.profile pulls a cached version of the profile when available? Thanks for reading.
Exhibit 1: myproject/myapp/models.py
def get_or_create_profile(u):
return cache_utils.cache_single_object(
"user_get_or_create_profile",
u.id, UserProfile.objects.get_or_create(user=u)[0])
User.profile = property(lambda u: cache_utils.cache_single_object(
"user_get_or_create_profile", u.id,
get_or_create_profile(u)))
Exhibit 2: myproject/cache_utils.py
def cache_single_object(key_prefix, id, query, timeout=500):
key = '%s_%s' % (key_prefix, id)
object_list = cache.get(key, None)
if object_list is None:
print "Miss %s" % (key)
object_list = query
cache.set(key, object_list, timeout)
else:
print "Hit %s" % (key)
return object_list
Exhibit 3: myproject/templates/mytemplate.py
<div>Example of what's in the template </div>
{{ myobject.owner.profile.bio }}
I think the problem is related to the way you defined your method….
when you access the profile property, you will always call the method get_or_create_profile(u) that calls:
having UserProfile.objects.get_or_create(user=u) there is what is creating your query every single time even if you already have the data in the cache. I think you should try using a util method where you don’t evaluate the query every time you call it. Maybe something like this: https://stackoverflow.com/a/2216326/234304