Browse Source

app: implement basic caching of long and/or frequent queries

Dennis Chen 2 years ago
parent
commit
fae5144626
2 changed files with 27 additions and 22 deletions
  1. 25 22
      app.py
  2. 2 0
      requirements.txt

+ 25 - 22
app.py

@@ -14,6 +14,8 @@ from flask import (
     url_for
 )
 
+from flask_caching import Cache
+
 from flask_login import LoginManager, UserMixin
 from flask_login import (
     current_user,
@@ -35,11 +37,13 @@ from pool import pool
 from settings import custom_settings
 from worker import xlsx_worker
 
+cache = Cache()
 login_manager = LoginManager()
 login_manager.login_view = 'login'
 login_manager.login_message_category = 'error'
 app = Flask(__name__)
 app.config.update(custom_settings)
+cache.init_app(app)
 login_manager.init_app(app)
 
 
@@ -69,18 +73,17 @@ class User(UserMixin):
         self.id = username
         self.first_name = ""
         self.last_name = ""
-        self._is_student = None
-        self._is_advisor = None
+
+    def __repr__(self):
+        return '%s' % self.id
 
     @property
     def email(self):
         return '%s@simons-rock.edu' % self.id
 
     @property
+    @cache.memoize()
     def is_student(self):
-        if self._is_student is not None:
-            return self._is_student
-
         is_student = False
         with pool.getconn() as conn:
             with conn.cursor() as curs:
@@ -89,14 +92,11 @@ class User(UserMixin):
                 if curs.fetchone() is not None:
                     is_student = True
         pool.putconn(conn)
-        self._is_student = is_student
-        return self._is_student
+        return is_student
 
     @property
+    @cache.memoize()
     def is_advisor(self):
-        if self._is_advisor is not None:
-            return self._is_advisor
-
         is_advisor = False
         with pool.getconn() as conn:
             with conn.cursor() as curs:
@@ -105,8 +105,7 @@ class User(UserMixin):
                 if curs.fetchone() is not None:
                     is_advisor = True
         pool.putconn(conn)
-        self._is_advisor = is_advisor
-        return self._is_advisor
+        return is_advisor
 
     @property
     def is_admin(self):
@@ -118,9 +117,6 @@ class User(UserMixin):
 class Student(User):
     def __init__(self, username):
         super().__init__(username)
-        self._is_student = True
-        self._is_advisor = False
-
         with pool.getconn() as conn:
             with conn.cursor() as curs:
                 curs.execute('''SELECT id, last_name, first_name, ar_units,
@@ -131,8 +127,6 @@ class Student(User):
                  self.advisor_id) = curs.fetchone()
         pool.putconn(conn)
 
-        self._advisor = None
-
     @property
     def advisor(self):
         if self._advisor is None:
@@ -172,9 +166,6 @@ class Student(User):
 class Advisor(User):
     def __init__(self, username):
         super().__init__(username)
-        self._is_student = False
-        self._is_advisor = True
-
         with pool.getconn() as conn:
             with conn.cursor() as curs:
                 curs.execute('''SELECT id, last_name, first_name FROM advisors
@@ -183,8 +174,6 @@ class Advisor(User):
                 self.advisor_id, self.last_name, self.first_name = curs.fetchone()
         pool.putconn(conn)
 
-        self._advisor = None
-
     @property
     def students(self):
         with pool.getconn() as conn:
@@ -213,6 +202,9 @@ class Event():
                 self.name, self.term, self.type = curs.fetchone()
         pool.putconn(conn)
 
+    def __repr__(self):
+        return 'Event(%s)' % self.id
+
     @property
     def students(self):
         with pool.getconn() as conn:
@@ -311,6 +303,7 @@ def event_show(id):
 
 @app.route('/leaderboard')
 @login_required
+@cache.cached(timeout=3600)
 def leaderboard():
     with pool.getconn() as conn:
         with conn.cursor() as curs:
@@ -359,6 +352,16 @@ def admin():
     return render_template('admin.html')
 
 
+@app.route('/admin/cache/bust')
+@login_required
+def bust_cache():
+    if not current_user.is_admin:
+        return abort(401)
+    cache.clear()
+    flash('Cache Cleared!', 'info')
+    return redirect(url_for('admin'))
+
+
 @app.route('/')
 def index():
     return render_template('index.html')

+ 2 - 0
requirements.txt

@@ -2,6 +2,7 @@ certifi==2017.4.17
 click==6.7
 et-xmlfile==1.0.1
 Flask==0.12.2
+Flask-Caching==1.3.2
 Flask-Login==0.4.0
 Flask-WTF==0.14.2
 gunicorn==19.7.1
@@ -12,6 +13,7 @@ MarkupSafe==1.0
 openpyxl==2.4.8
 psycopg2==2.7.1
 python-dateutil==2.6.0
+redis==2.10.5
 six==1.10.0
 sr-auth==1.0.1
 urllib3==1.21.1