Merge pull request #3419 from FinnStutzenstein/ViewCaching

Index and Webclient View caching
This commit is contained in:
Emanuel Schütze 2017-09-27 13:21:46 +02:00 committed by GitHub
commit c269ae5cf8
4 changed files with 48 additions and 28 deletions

View File

@ -85,6 +85,8 @@ Core:
- Added custom translations in config [#3383]. - Added custom translations in config [#3383].
- Added dynamic webpage title [#3404]. - Added dynamic webpage title [#3404].
- Added 'go to top'-link [#3404]. - Added 'go to top'-link [#3404].
- Added caching for the index views. When using a Webserver for serving
static files see the example configuration in the PR [#3419].
Mediafiles: Mediafiles:
- Fixed reloading of PDF on page change [#3274]. - Fixed reloading of PDF on page change [#3274].

View File

@ -3,11 +3,10 @@ import uuid
from collections import OrderedDict from collections import OrderedDict
from operator import attrgetter from operator import attrgetter
from textwrap import dedent from textwrap import dedent
from typing import Any, Dict, List # noqa from typing import Any, Dict, List, cast # noqa
from django.apps import apps from django.apps import apps
from django.conf import settings from django.conf import settings
from django.contrib.staticfiles import finders
from django.db.models import F from django.db.models import F
from django.http import Http404, HttpResponse from django.http import Http404, HttpResponse
from django.utils.timezone import now from django.utils.timezone import now
@ -54,7 +53,7 @@ from .models import (
# Special Django views # Special Django views
class IndexView(utils_views.CSRFMixin, utils_views.View): class IndexView(utils_views.CSRFMixin, utils_views.IndexView):
""" """
The primary view for OpenSlides using AngularJS. The primary view for OpenSlides using AngularJS.
@ -62,28 +61,20 @@ class IndexView(utils_views.CSRFMixin, utils_views.View):
You can override it by simply adding a custom 'templates/index.html' file You can override it by simply adding a custom 'templates/index.html' file
to the custom staticfiles directory. See STATICFILES_DIRS in settings.py. to the custom staticfiles directory. See STATICFILES_DIRS in settings.py.
""" """
template_name = 'templates/index.html'
def get(self, *args, **kwargs):
with open(finders.find('templates/index.html')) as f:
content = f.read()
return HttpResponse(content)
class ProjectorView(utils_views.View): class ProjectorView(utils_views.IndexView):
""" """
The primary view for OpenSlides projector using AngularJS. The primary view for OpenSlides projector using AngularJS.
The projector container template is 'openslides/core/static/templates/projector-container.html'. The projector container template is 'openslides/core/static/templates/projector-container.html'.
This container is for controlling the projector resolution. This container is for controlling the projector resolution.
""" """
template_name = 'templates/projector-container.html'
def get(self, *args, **kwargs):
with open(finders.find('templates/projector-container.html')) as f:
content = f.read()
return HttpResponse(content)
class RealProjectorView(utils_views.View): class RealProjectorView(utils_views.IndexView):
""" """
The original view without resolutioncontrol for OpenSlides projector using AngularJS. The original view without resolutioncontrol for OpenSlides projector using AngularJS.
@ -92,11 +83,7 @@ class RealProjectorView(utils_views.View):
file to the custom staticfiles directory. See STATICFILES_DIRS in file to the custom staticfiles directory. See STATICFILES_DIRS in
settings.py. settings.py.
""" """
template_name = 'templates/projector.html'
def get(self, *args, **kwargs):
with open(finders.find('templates/projector.html')) as f:
content = f.read()
return HttpResponse(content)
class WebclientJavaScriptView(utils_views.View): class WebclientJavaScriptView(utils_views.View):
@ -105,10 +92,15 @@ class WebclientJavaScriptView(utils_views.View):
AngularJS app for the requested realm (site or projector). Also code AngularJS app for the requested realm (site or projector). Also code
for plugins is appended. The result is not uglified. for plugins is appended. The result is not uglified.
""" """
def get(self, *args, **kwargs): def __init__(self, *args: Any, **kwargs: Any) -> None:
angular_modules = [] super().__init__(*args, **kwargs)
self.cache = {} # type: Dict[str, str]
self.init_cache('site')
self.init_cache('projector')
def init_cache(self, realm: str) -> None:
angular_modules = [] # type: List[str]
js_files = [] # type: List[str] js_files = [] # type: List[str]
realm = kwargs.get('realm') # Result is 'site' or 'projector'
for app_config in apps.get_app_configs(): for app_config in apps.get_app_configs():
# Add the angular app if the module has one. # Add the angular app if the module has one.
if getattr(app_config, 'angular_{}_module'.format(realm), False): if getattr(app_config, 'angular_{}_module'.format(realm), False):
@ -187,8 +179,11 @@ class WebclientJavaScriptView(utils_views.View):
""" """
}()); }());
""") """)
self.cache[realm] = content
return HttpResponse(content, content_type='application/javascript') def get(self, *args: Any, **kwargs: Any) -> HttpResponse:
realm = cast(str, kwargs.get('realm')) # Result is 'site' or 'projector'
return HttpResponse(self.cache[realm], content_type='application/javascript')
# Viewsets for the REST API # Viewsets for the REST API

View File

@ -1,5 +1,8 @@
from typing import Any, Dict, List # noqa from typing import Any, Dict, List # noqa
from django.contrib.staticfiles import finders
from django.core.exceptions import ImproperlyConfigured
from django.http import HttpResponse
from django.views.decorators.csrf import ensure_csrf_cookie from django.views.decorators.csrf import ensure_csrf_cookie
from django.views.generic.base import View from django.views.generic.base import View
from rest_framework.response import Response from rest_framework.response import Response
@ -45,3 +48,22 @@ class APIView(_APIView):
# Add the http-methods and delete the method "method_call" # Add the http-methods and delete the method "method_call"
get = post = put = patch = delete = head = options = trace = method_call get = post = put = patch = delete = head = options = trace = method_call
del method_call del method_call
class IndexView(View):
"""
A view to serve a single cached template file. Subclasses has to provide 'template_name'.
"""
template_name = None # type: str
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
if self.template_name is None:
raise ImproperlyConfigured("'template_name' is not provided")
with open(finders.find(self.template_name)) as template:
self.template = template.read()
def get(self, *args: Any, **kwargs: Any) -> HttpResponse:
return HttpResponse(self.template)

View File

@ -169,10 +169,11 @@ class ProjectorAPI(TestCase):
class WebclientJavaScriptView(TestCase): class WebclientJavaScriptView(TestCase):
def setUp(self): def setUp(self):
self.request = MagicMock() self.request = MagicMock()
self.view_instance = views.WebclientJavaScriptView()
self.view_instance.request = self.request
@patch('django.contrib.auth.models.Permission.objects.all') @patch('django.contrib.auth.models.Permission.objects.all')
def test_permissions_as_constant(self, mock_all): def test_permissions_as_constant(self, mock_all):
self.view_instance.get() self.view_instance = views.WebclientJavaScriptView()
self.assertEqual(mock_all.call_count, 1) self.view_instance.request = self.request
response = self.view_instance.get(realm='site')
self.assertEqual(response.status_code, 200)
self.assertEqual(mock_all.call_count, 2)