# HG changeset patch # User neko259 # Date 2015-04-17 15:44:45 # Node ID 2a693c119a64f9a0ceeaa9dcd0aa60e71ea9d462 # Parent 08b1f6e610662f73a558bade243692e4ef96670c Added ability to cache method result with additional arguments. Cache thread reply count and images count diff --git a/boards/models/post.py b/boards/models/post.py --- a/boards/models/post.py +++ b/boards/models/post.py @@ -122,7 +122,7 @@ class PostManager(models.Manager): for post in posts: post.delete() - @cached_result + @cached_result() def get_posts_per_day(self) -> float: """ Gets average count of posts per day for the last 7 days @@ -209,7 +209,7 @@ class Post(models.Model, Viewable): return self.get_thread().get_opening_post_id() == self.id - @cached_result + @cached_result() def get_url(self): """ Gets full url to the post. diff --git a/boards/models/thread.py b/boards/models/thread.py --- a/boards/models/thread.py +++ b/boards/models/thread.py @@ -7,7 +7,7 @@ from django.db import models from boards import settings import boards -from boards.utils import cached_result +from boards.utils import cached_result, datetime_to_epoch from boards.models.post import Post from boards.models.tag import Tag @@ -94,9 +94,14 @@ class Thread(models.Model): self.bumpable = False self.update_posts_time() + def _get_cache_key(self): + return [datetime_to_epoch(self.last_edit_time)] + + @cached_result(key_method=_get_cache_key) def get_reply_count(self) -> int: return self.get_replies().count() + @cached_result(key_method=_get_cache_key) def get_images_count(self) -> int: return self.get_replies().annotate(images_count=Count( 'images')).aggregate(Sum('images_count'))['images_count__sum'] @@ -152,6 +157,7 @@ class Thread(models.Model): return self.get_replies(view_fields_only).annotate(images_count=Count( 'images')).filter(images_count__gt=0) + # TODO Do we still need this? def add_tag(self, tag: Tag): """ Connects thread to a tag and tag to a thread @@ -171,7 +177,7 @@ class Thread(models.Model): return opening_post - @cached_result + @cached_result() def get_opening_post_id(self) -> int: """ Gets ID of the first thread post. @@ -217,4 +223,4 @@ class Thread(models.Model): client.publish(channel_name, { WS_NOTIFICATION_TYPE: WS_NOTIFICATION_TYPE_NEW_POST, }) - client.send() \ No newline at end of file + client.send() diff --git a/boards/templates/boards/thread.html b/boards/templates/boards/thread.html --- a/boards/templates/boards/thread.html +++ b/boards/templates/boards/thread.html @@ -1,7 +1,6 @@ {% extends "boards/base.html" %} {% load i18n %} -{% load cache %} {% load static from staticfiles %} {% load board %} {% load tz %} @@ -13,9 +12,6 @@ {% block metapanel %} - {% get_current_language as LANGUAGE_CODE %} - {% get_current_timezone as TIME_ZONE %} - {{ thread.get_reply_count }}{% if thread.has_post_limit %}/{{ thread.max_posts }}{% endif %} {% trans 'messages' %}, {{ thread.get_images_count }} {% trans 'images' %}. {% trans 'Last update: ' %} [RSS] - {% endcache %} {% endblock %} diff --git a/boards/utils.py b/boards/utils.py --- a/boards/utils.py +++ b/boards/utils.py @@ -3,6 +3,8 @@ This module contains helper functions an """ import time import hmac +import functools + from django.core.cache import cache from django.db.models import Model @@ -11,9 +13,7 @@ from django.utils import timezone from neboard import settings -KEY_CAPTCHA_FAILS = 'key_captcha_fails' -KEY_CAPTCHA_DELAY_TIME = 'key_captcha_delay_time' -KEY_CAPTCHA_LAST_ACTIVITY = 'key_captcha_last_activity' +CACHE_KEY_DELIMITER = '_' def get_client_ip(request): @@ -46,24 +46,31 @@ def get_websocket_token(user_id='', time return token -def cached_result(function): +def cached_result(key_method=None): """ Caches method result in the Django's cache system, persisted by object name, object name and model id if object is a Django model. """ - def inner_func(obj, *args, **kwargs): - # TODO Include method arguments to the cache key - cache_key = obj.__class__.__name__ + '_' + function.__name__ - if isinstance(obj, Model): - cache_key += '_' + str(obj.id) + def _cached_result(function): + def inner_func(obj, *args, **kwargs): + # TODO Include method arguments to the cache key + cache_key_params = [obj.__class__.__name__, function.__name__] + if isinstance(obj, Model): + cache_key_params.append(str(obj.id)) + + if key_method is not None: + cache_key_params += [str(arg) for arg in key_method(obj)] + + cache_key = CACHE_KEY_DELIMITER.join(cache_key_params) - persisted_result = cache.get(cache_key) - if persisted_result: - result = persisted_result - else: - result = function(obj, *args, **kwargs) - cache.set(cache_key, result) + persisted_result = cache.get(cache_key) + if persisted_result is not None: + result = persisted_result + else: + result = function(obj, *args, **kwargs) + cache.set(cache_key, result) - return result + return result - return inner_func + return inner_func + return _cached_result