Skip to content

Commit 9025210

Browse files
Implement caching for homepage data and signals to improve performance (#75)
* Implement caching for homepage data and signals to improve performance - Added caching for categories, recent questions, active questions, slider questions, spam questions, and category question mapping in views. - Introduced a cache invalidation mechanism in signals for questions and answers. - Updated the settings to include cache configuration. - Enhanced template tags to cache total question and answer counts. - Refactored the category image retrieval to utilize caching. * Update caching configuration and improve homepage data retrieval - Changed cache backend to Memcached and added a file cache option in settings. - Increased HOME_CACHE_TIMEOUT to 3600 seconds for better performance. - Refactored homepage data retrieval functions to accept a base queryset, enhancing flexibility and efficiency. - Updated calls to caching functions to utilize the new base queryset parameter. * Refactor caching configuration to support Memcached and local memory fallback - Updated the caching settings to use Memcached if available, otherwise default to local memory for development. - Simplified cache backend configuration by defining a single variable for the default cache settings. * Enhance user data caching and template rendering for performance improvements - Updated templates to utilize cached user data for questions, answers, and notifications, reducing database queries. - Refactored views to attach cached usernames to questions and answers, improving efficiency in rendering. - Implemented caching for question counts in template tags to speed up category data retrieval. - Adjusted notification rendering to leverage cached attributes, minimizing additional database lookups. --------- Co-authored-by: ankitamk14 <ankitamk@gmail.com>
1 parent 11e6d10 commit 9025210

12 files changed

Lines changed: 218 additions & 97 deletions

File tree

static/website/templates/ajax-keyword-search.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,16 @@
6363
</td>
6464

6565
<td>
66-
{{ question.views}}
66+
{{ question.views }}
6767
</td>
6868

6969
<td>
70-
{{ question.answer_set.count }}
70+
{{ question.total_answers }}
7171
</td>
7272

7373
<td>
74-
<span class="title" data-toggle="tooltip" data-placement="top" title="{{ question.user }}">
75-
{{ question.user|truncatechars:10 }}
74+
<span class="title" data-toggle="tooltip" data-placement="top" title="{{ question.cached_user|default:question.user }}">
75+
{{ question.cached_user|default:question.user|truncatechars:10 }}
7676
</span>
7777
</td>
7878

static/website/templates/ajax-time-search.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,16 @@
6161
</td>
6262

6363
<td>
64-
{{ question.views}}
64+
{{ question.views }}
6565
</td>
6666

6767
<td>
68-
{{ question.answer_set.count }}
68+
{{ question.total_answers }}
6969
</td>
7070

7171
<td>
72-
<span class="title" data-toggle="tooltip" data-placement="top" title="{{ question.user }}">
73-
{{ question.user|truncatechars:10 }}
72+
<span class="title" data-toggle="tooltip" data-placement="top" title="{{ question.cached_user|default:question.user }}">
73+
{{ question.cached_user|default:question.user|truncatechars:10 }}
7474
</span>
7575
</td>
7676

static/website/templates/filter.html

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,16 @@ <h5>
8282
</td>
8383

8484
<td>
85-
{{ question.views}}
85+
{{ question.views }}
8686
</td>
87-
87+
8888
<td>
89-
{{ question.answer_set.count }}
89+
{{ question.total_answers }}
9090
</td>
91-
91+
9292
<td>
93-
<span class="title" data-toggle="tooltip" data-placement="top" title="{{ question.user }}">
94-
{{ question.user|truncatechars:10 }}
93+
<span class="title" data-toggle="tooltip" data-placement="top" title="{{ question.cached_user|default:question.user }}">
94+
{{ question.cached_user|default:question.user|truncatechars:10 }}
9595
</span>
9696
</td>
9797

static/website/templates/get-question.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ <h5>Question</h5>
136136
</small>
137137

138138
<span class="user">
139-
{{ question.user }}
139+
{{ question.cached_user|default:question.user }}
140140
</span>
141141
</span>
142142
</div> <!-- /.question -->
@@ -169,7 +169,7 @@ <h4><u>Answers:</u></h4>
169169
</small>
170170

171171
<span class="user">
172-
{{ answer.user }}
172+
{{ answer.cached_user|default:answer.user }}
173173
</span>
174174
</span>
175175
{% if user|can_edit:answer %}
@@ -199,7 +199,7 @@ <h4><u>Answers:</u></h4>
199199
</small>
200200

201201
<span class="user">
202-
{{ comment.user }}
202+
{{ comment.cached_user|default:comment.user }}
203203
</span>
204204
</span>
205205
{% if user|can_edit:comment %}

static/website/templates/notifications.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ <h4 class="pull-left">Notifications</h4>
77
</a>
88
<div class="clearfix"></div>
99
{% for notification in notifications %}
10-
{% get_notification notification.id %}
10+
{% get_notification notification %}
1111
{% endfor %}
1212
{% endblock %}
1313

static/website/templates/questions.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,16 @@ <h5>
6868
</td>
6969

7070
<td class="col-md-1">
71-
{{ question.views}}
71+
{{ question.views }}
7272
</td>
7373

7474
<td class="col-md-1">
75-
{{ question.answer_set.count }}
75+
{{ question.total_answers }}
7676
</td>
7777

7878
<td class="col-md-1">
79-
<span class="title" data-toggle="tooltip" data-placement="top" title="{{ question.user }}">
80-
{{ question.user|truncatechars:10 }}
79+
<span class="title" data-toggle="tooltip" data-placement="top" title="{{ question.cached_user|default:question.user }}">
80+
{{ question.cached_user|default:question.user|truncatechars:10 }}
8181
</span>
8282
</td>
8383
</tr>

static/website/templates/recent-questions.html

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
{% extends 'website/templates/base.html' %}
21
{% load static %}
32
{% load count_tags %}
43

5-
{% block content %}
6-
<h4><u>Recent Questions</u></h4>
4+
<h4><u>Recent Questions</u></h4>
75
<table class="table table-bordered table-hover">
86
<th> FOSS </th>
97
<th> Tutorial</th>
@@ -65,16 +63,16 @@ <h4><u>Recent Questions</u></h4>
6563
</td>
6664

6765
<td>
68-
{{ question.views}}
66+
{{ question.views }}
6967
</td>
7068

7169
<td>
72-
{{ question.answer_set.count }}
70+
{{ question.total_answers }}
7371
</td>
7472

7573
<td>
76-
<span class="title" data-toggle="tooltip" data-placement="top" title="{{ question.user }}">
77-
{{ question.user|truncatechars:10 }}
74+
<span class="title" data-toggle="tooltip" data-placement="top" title="{{ question.cached_user|default:question.user }}">
75+
{{ question.cached_user|default:question.user|truncatechars:10 }}
7876
</span>
7977
</td>
8078
</tr>
@@ -96,11 +94,6 @@ <h4><u>Recent Questions</u></h4>
9694
{% endfor %}
9795
</ul>
9896
{% endif %}
99-
100-
{% endblock %}
101-
102-
{% block javascript %}
10397
<script>
10498
$('span').tooltip();
10599
</script>
106-
{% endblock %}

website/models.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,22 @@ class Question(models.Model):
2121
# votes = models.IntegerField(default=0)
2222

2323
def user(self):
24+
cached_username = getattr(self, "cached_user", None)
25+
if cached_username is not None:
26+
return cached_username
2427
user = User.objects.get(id=self.uid)
25-
return user.username
28+
username = user.username
29+
self.cached_user = username
30+
return username
2631

2732
def last_post_user(self):
33+
cached_username = getattr(self, "cached_last_post_user", None)
34+
if cached_username is not None:
35+
return cached_username
2836
user = User.objects.filter(id=self.last_post_by).first()
29-
return user.username if user else "Unknown User"
37+
username = user.username if user else "Unknown User"
38+
self.cached_last_post_user = username
39+
return username
3040

3141
class Meta:
3242
get_latest_by = "date_created"
@@ -54,8 +64,13 @@ class Answer(models.Model):
5464
# votes = models.IntegerField(default=0)
5565

5666
def user(self):
67+
cached_username = getattr(self, "cached_user", None)
68+
if cached_username is not None:
69+
return cached_username
5770
user = User.objects.get(id=self.uid)
58-
return user.username
71+
username = user.username
72+
self.cached_user = username
73+
return username
5974

6075

6176
class AnswerVote(models.Model):
@@ -71,8 +86,13 @@ class AnswerComment(models.Model):
7186
date_modified = models.DateTimeField(auto_now=True)
7287

7388
def user(self):
89+
cached_username = getattr(self, "cached_user", None)
90+
if cached_username is not None:
91+
return cached_username
7492
user = User.objects.get(id=self.uid)
75-
return user.username
93+
username = user.username
94+
self.cached_user = username
95+
return username
7696

7797

7898
class Notification(models.Model):
@@ -84,7 +104,12 @@ class Notification(models.Model):
84104
date_created = models.DateTimeField(auto_now_add=True)
85105

86106
def poster(self):
107+
cached_username = getattr(self, "cached_poster", None)
108+
if cached_username is not None:
109+
return cached_username
87110
user = User.objects.get(id=self.pid)
88-
return user.username
111+
username = user.username
112+
self.cached_poster = username
113+
return username
89114

90115
# CDEEP database created using inspectdb arg of manage.py

website/templatetags/count_tags.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,16 @@
66
register = template.Library()
77

88

9-
# Counts the number of questions in <category>
9+
# Counts the number of questions in <category>, cached for faster rendering
1010
def category_question_count(category):
11-
category_question_count = Question.objects.filter(category=category).count()
12-
return category_question_count
11+
cache_key = f"stats:category_question_count:{category}"
12+
count = cache.get(cache_key)
13+
if count is not None:
14+
return count
15+
16+
count = Question.objects.filter(category=category).count()
17+
cache.set(cache_key, count, 300)
18+
return count
1319

1420

1521
register.simple_tag(category_question_count)

website/templatetags/notify.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@
55
register = template.Library()
66

77

8-
def get_notification(nid):
9-
notification = Notification.objects.get(pk=nid)
10-
try:
11-
question = Question.objects.get(pk=notification.qid)
12-
except Question.DoesNotExist:
13-
question = None
14-
try:
15-
answer = Answer.objects.get(pk=notification.aid)
16-
except Answer.DoesNotExist:
17-
answer = None
8+
def get_notification(notification):
9+
"""
10+
Render a single notification.
11+
12+
The view (`user_notifications`) attaches `cached_question`, `cached_answer`
13+
and `cached_poster` attributes on each `Notification` instance so that this
14+
tag does not need to perform any additional database queries.
15+
"""
16+
question = getattr(notification, "cached_question", None)
17+
answer = getattr(notification, "cached_answer", None)
1818
context = {
1919
'notification': notification,
2020
'question': question,

0 commit comments

Comments
 (0)