misc: cache get_page_choices result during a request (#19015)

This commit is contained in:
Frédéric Péters 2017-09-27 14:03:52 +02:00
parent bed9817392
commit dfa44aaf6d
5 changed files with 100 additions and 0 deletions

View File

@ -21,6 +21,9 @@ from django import forms
from .models import Page, ParametersCell, MenuCell, LinkCell, ConfigJsonCell
from jsonfield.widgets import JSONWidget
from combo.utils import cache_during_request
class ParametersForm(forms.Form):
choice = forms.ChoiceField(choices=[])
@ -53,6 +56,7 @@ class ParametersCellForm(forms.ModelForm):
}
@cache_during_request
def get_page_choices():
pages = Page.get_as_reordered_flat_hierarchy(Page.objects.all())
return [(x.id, '%s %s' % (u'\u00a0' * x.level * 2, x.title)) for x in pages]

36
combo/middleware.py Normal file
View File

@ -0,0 +1,36 @@
# combo - content management system
# Copyright (C) 2017 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import threading
_requests = {}
def get_request():
return _requests.get(threading.current_thread())
class GlobalRequestMiddleware(object):
def process_request(self, request):
_requests[threading.current_thread()] = request
request.cache = {}
def process_response(self, request, response):
del _requests[threading.current_thread()]
return response
def process_exception(self, request, exception):
return self.process_response(request, None)

View File

@ -89,6 +89,7 @@ INSTALLED_APPS = (
INSTALLED_APPS = plugins.register_plugins_apps(INSTALLED_APPS)
MIDDLEWARE_CLASSES = (
'combo.middleware.GlobalRequestMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',

View File

@ -39,6 +39,8 @@ from django.template import Context
from django.utils.html import strip_tags
from django.utils.http import urlencode, quote
from .middleware import get_request
class DecryptionError(Exception):
pass
@ -280,3 +282,42 @@ def check_string(s, signature, keys, algo='sha256'):
if res == 0:
return True
return False
# _make_key and _HashedSeq imported/adapted from functools from Python 3.2+
def _make_key(args, kwds,
kwd_mark=(object(),),
fasttypes={int, str, frozenset, type(None)},
tuple=tuple, type=type, len=len):
key = args
if kwds:
key += kwd_mark
for item in kwds.items():
key += item
if len(key) == 1 and type(key[0]) in fasttypes:
return key[0]
return _HashedSeq(key)
class _HashedSeq(list):
__slots__ = 'hashvalue'
def __init__(self, tup, hash=hash):
self[:] = tup
self.hashvalue = hash(tup)
def __hash__(self):
return self.hashvalue
def cache_during_request(func):
def inner(*args, **kwargs):
request = get_request()
if request:
cache_key = (id(func), _make_key(args, kwargs))
if cache_key in request.cache:
return request.cache[cache_key]
result = func(*args, **kwargs)
if request:
request.cache[cache_key] = result
return result
return inner

View File

@ -3,6 +3,8 @@ import os
import StringIO
import urllib
import mock
from django.core.files.storage import default_storage
from django.conf import settings
from django.contrib.auth.models import User
@ -585,3 +587,19 @@ def test_menu_json(app, admin_user):
resp = app.get('/manage/menu.json?callback=fooBar')
assert resp.headers['content-type'] == 'application/javascript'
assert resp.content.startswith('fooBar([{"')
def test_page_multiple_link_cells(app, admin_user):
Page.objects.all().delete()
page = Page(title='One', slug='one', template_name='standard')
page.save()
for i in range(10):
Page(title='page %d' % i, slug='page%d' % i, template_name='standard').save()
cell = LinkCell(page=page, placeholder='content', order=0)
cell.save()
patched_orig = Page.get_as_reordered_flat_hierarchy
app = login(app)
with mock.patch('combo.data.models.Page.get_as_reordered_flat_hierarchy') as func:
func.return_value = []
resp = app.get('/manage/pages/%s/' % page.id)
assert func.call_count == 1