Skip to content

Commit

Permalink
Adding view caching
Browse files Browse the repository at this point in the history
  • Loading branch information
= committed Nov 14, 2024
1 parent 2fa0c15 commit 1425c95
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 14 deletions.
21 changes: 21 additions & 0 deletions crank/decorators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright (c) 2024 Isaac Adams
# Licensed under the MIT License. See LICENSE file in the project root for full license information.
from functools import wraps

from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page

def cache_page_if_anonymous_method(timeout, view_func=None):
def decorator(view_func):
@wraps(view_func)
def _wrapped_view(request, *args, **kwargs):
if request.user.is_authenticated:
return view_func(request, *args, **kwargs)
return cache_page(timeout)(view_func)(request, *args, **kwargs)
return _wrapped_view

def class_decorator(cls):
cls.dispatch = method_decorator(decorator, name='dispatch')(cls.dispatch)
return cls

return class_decorator if isinstance(view_func, type) else decorator
2 changes: 1 addition & 1 deletion crank/models/organization.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class RTOPolicy(TextChoices):
def avg_scores(self):
cache_key = f'organization_{self.pk}_avg_scores'
return cache.get_or_set(cache_key, lambda: self.scores.values("type__name").annotate(avg_score=Avg('score')),
timeout=settings.CACHE_TIMEOUT)
timeout=settings.CACHE_MIDDLEWARE_SECONDS)

@staticmethod
def get_funding_round_choices():
Expand Down
14 changes: 11 additions & 3 deletions crank/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import os
from pathlib import Path

from django.conf.global_settings import STATICFILES_DIRS
from django.conf.global_settings import STATICFILES_DIRS, CACHE_MIDDLEWARE_SECONDS
from django.contrib.staticfiles.storage import ManifestStaticFilesStorage
from dotenv import load_dotenv
from opentelemetry.instrumentation.django import DjangoInstrumentor
Expand Down Expand Up @@ -155,21 +155,29 @@
SESSION_SAVE_EVERY_REQUEST = False
SESSION_COOKIE_DOMAIN = ".crank.fyi"
SESSION_COOKIE_SECURE = False
# Set session timeout to 30 minutes
SESSION_COOKIE_AGE = 1800 # 30 minutes in seconds

CACHE_TIMEOUT = 20 # Timeout for Redis cached items in seconds
CACHE_MIDDLEWARE_SECONDS = 60 # Timeout for cached items in seconds
REDIS_URL = os.environ["REDIS_URL"]
# Optional: To use Redis for session storage
SESSION_CACHE_ALIAS = 'default'
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': REDIS_URL,
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
'SOCKET_CONNECT_TIMEOUT': 5, # in seconds
'SOCKET_TIMEOUT': 5, # in seconds
}
}
}

# Set the TTL for session entries in Redis
SESSION_REDIS = {
'ttl': 1800, # 30 minutes in seconds
}

# Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators

Expand Down
2 changes: 1 addition & 1 deletion crank/settings/prod.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

DATABASES = {
'default': {
'ENGINE': 'dj_db_conn_pool.backends.mysql',
'ENGINE': 'django.db.backends.mysql',
'NAME': os.environ.get('DB_NAME'),
'HOST': os.environ.get('DB_HOST'),
'PORT': os.environ.get('DB_PORT'),
Expand Down
15 changes: 9 additions & 6 deletions crank/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,25 @@
from allauth.account.views import LogoutView
from django.contrib import admin
from django.urls import path, include
from django.conf import settings

from crank.decorators import cache_page_if_anonymous_method
from crank.views.fundinground import FundingRoundChoicesView
from crank.views.rtopolicy import RTOPolicyChoicesView
from crank.views.index import IndexView
from crank.views.organization import OrganizationView
from crank.views.logout import CustomLogoutView

app_name = "crank"

urlpatterns = [
path("", IndexView.as_view(), name="index"),
path("", cache_page_if_anonymous_method(settings.CACHE_MIDDLEWARE_SECONDS)(IndexView.as_view()), name="index"),
path("admin/", admin.site.urls),
path("algo/<int:algorithm_id>/", IndexView.as_view(), name="index"),
path("organization/<int:pk>/", OrganizationView.as_view(), name="organization"),
path('api/funding-round-choices/', FundingRoundChoicesView.as_view(), name='funding_round_choices'),
path('api/rto-policy-choices/', RTOPolicyChoicesView.as_view(), name='rto_policy_choices'),
path("algo/<int:algorithm_id>/", cache_page_if_anonymous_method(settings.CACHE_MIDDLEWARE_SECONDS)(IndexView.as_view()), name="index"),
path("organization/<int:pk>/", cache_page_if_anonymous_method(settings.CACHE_MIDDLEWARE_SECONDS)(OrganizationView.as_view()), name="organization"),
path('api/funding-round-choices/', cache_page_if_anonymous_method(settings.CACHE_MIDDLEWARE_SECONDS)(FundingRoundChoicesView.as_view()), name='funding_round_choices'),
path('api/rto-policy-choices/', cache_page_if_anonymous_method(settings.CACHE_MIDDLEWARE_SECONDS)(RTOPolicyChoicesView.as_view()), name='rto_policy_choices'),
path('api-auth/', include('rest_framework.urls')),
path('accounts/logout/', CustomLogoutView.as_view(), name='account_logout'),
path('accounts/', include('allauth.urls')),
path('logout', LogoutView.as_view())
]
2 changes: 1 addition & 1 deletion crank/views/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def fetch_results():
return object_list

cache_key = f'algorithm_{self.algorithm_id}_results'
self.object_list = cache.get_or_set(cache_key, fetch_results, timeout=settings.CACHE_TIMEOUT)
self.object_list = cache.get_or_set(cache_key, fetch_results, timeout=settings.CACHE_MIDDLEWARE_SECONDS)
return self.object_list


Expand Down
13 changes: 13 additions & 0 deletions crank/views/logout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright (c) 2024 Isaac Adams
# Licensed under the MIT License. See LICENSE file in the project root for full license information.
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from allauth.account.views import LogoutView as AllauthLogoutView
from django.shortcuts import redirect, render


@method_decorator(csrf_exempt, name='dispatch')
class CustomLogoutView(AllauthLogoutView):
def post(self, request, *args, **kwargs):
_ = super().post(request, *args, **kwargs)
return redirect('index') # Redirect to home page after logout
2 changes: 1 addition & 1 deletion crank/views/organization.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ def get_object(self, queryset=None):
obj_id = self.kwargs.get('pk')
cache_key = f'organization_{obj_id}'
return cache.get_or_set(cache_key, lambda: super(OrganizationView, self).get_object(queryset),
timeout=settings.CACHE_TIMEOUT)
timeout=settings.CACHE_MIDDLEWARE_SECONDS)
5 changes: 4 additions & 1 deletion templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@
{% if user.is_staff %}
<a class="btn btn-primary btn-sm" href="/admin">Admin</a>
{% endif %}
<a class="btn btn-secondary btn-sm" href="/logout">Logout {{ user.username }}</a>
<form method="post" action="{% url 'account_logout' %}" style="display:inline;">
{% csrf_token %}
<button class="btn btn-secondary btn-sm" type="submit">Logout {{ user.username }}</button>
</form>
{% else %}
<a class="btn btn-light btn-sm" href="{% provider_login_url 'google' %}">
<i class="fab fa-google"></i>
Expand Down

0 comments on commit 1425c95

Please sign in to comment.