misc: cache get_page_choices result during a request (#19015)
This commit is contained in:
parent
bed9817392
commit
dfa44aaf6d
|
@ -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]
|
||||
|
|
|
@ -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)
|
|
@ -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',
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue