Browse Source

Refactored monitor to behave like settings do. #161

Ralfp 12 years ago
parent
commit
0cfdc474ef

+ 3 - 2
misago/acl/builder.py

@@ -3,6 +3,7 @@ from django.core.cache import cache, InvalidCacheBackendError
 from django.utils.importlib import import_module
 from django.utils.importlib import import_module
 from misago.forms import Form
 from misago.forms import Form
 from misago.models import Forum, ForumRole
 from misago.models import Forum, ForumRole
+from misago.monitor import monitor
 
 
 def build_form(request, role):
 def build_form(request, role):
     form_type = type('ACLForm', (Form,), dict(layout=[]))
     form_type = type('ACLForm', (Form,), dict(layout=[]))
@@ -50,7 +51,7 @@ def acl(request, user):
     acl_key = user.make_acl_key()
     acl_key = user.make_acl_key()
     try:
     try:
         user_acl = cache.get(acl_key)
         user_acl = cache.get(acl_key)
-        if user_acl.version != request.monitor['acl_version']:
+        if user_acl.version != monitor.acl_version:
             raise InvalidCacheBackendError()
             raise InvalidCacheBackendError()
     except (AttributeError, InvalidCacheBackendError):
     except (AttributeError, InvalidCacheBackendError):
         user_acl = build_acl(request, user.get_roles())
         user_acl = build_acl(request, user.get_roles())
@@ -59,7 +60,7 @@ def acl(request, user):
 
 
 
 
 def build_acl(request, roles):
 def build_acl(request, roles):
-    new_acl = ACL(request.monitor['acl_version'])
+    new_acl = ACL(monitor.acl_version)
     forums = Forum.objects.get(special='root').get_descendants().order_by('lft')
     forums = Forum.objects.get(special='root').get_descendants().order_by('lft')
     perms = []
     perms = []
     forum_roles = {}
     forum_roles = {}

+ 1 - 1
misago/apps/activation/views.py

@@ -77,7 +77,7 @@ def activate(request, username="", user="0", token=""):
         sign_user_in(request, user)
         sign_user_in(request, user)
 
 
         # Update monitor
         # Update monitor
-        User.objects.resync_monitor(request.monitor)
+        User.objects.resync_monitor()
 
 
         if current_activation == User.ACTIVATION_CREDENTIALS:
         if current_activation == User.ACTIVATION_CREDENTIALS:
             return redirect_message(request, Message(_("%(username)s, your account has been successfully reactivated after change of sign-in credentials.") % {'username': user.username}), 'success')
             return redirect_message(request, Message(_("%(username)s, your account has been successfully reactivated after change of sign-in credentials.") % {'username': user.username}), 'success')

+ 9 - 4
misago/apps/admin/bans/views.py

@@ -6,6 +6,7 @@ from misago.admin import site
 from misago.apps.admin.widgets import *
 from misago.apps.admin.widgets import *
 from misago.messages import Message
 from misago.messages import Message
 from misago.models import Ban
 from misago.models import Ban
+from misago.monitor import monitor, UpdatingMonitor
 from misago.apps.admin.bans.forms import BanForm, SearchBansForm
 from misago.apps.admin.bans.forms import BanForm, SearchBansForm
 
 
 def reverse(route, target=None):
 def reverse(route, target=None):
@@ -58,7 +59,8 @@ class List(ListWidget):
 
 
     def action_delete(self, items, checked):
     def action_delete(self, items, checked):
         Ban.objects.filter(id__in=checked).delete()
         Ban.objects.filter(id__in=checked).delete()
-        self.request.monitor.increase('bans_version')
+        with UpdatingMonitor() as cm:
+            monitor.increase('bans_version')
         return Message(_('Selected bans have been lifted successfully.'), 'success'), reverse('admin_bans')
         return Message(_('Selected bans have been lifted successfully.'), 'success'), reverse('admin_bans')
 
 
 
 
@@ -87,7 +89,8 @@ class New(FormWidget):
                       expires=form.cleaned_data['expires']
                       expires=form.cleaned_data['expires']
                      )
                      )
         new_ban.save(force_insert=True)
         new_ban.save(force_insert=True)
-        self.request.monitor.increase('bans_version')
+        with UpdatingMonitor() as cm:
+            monitor.increase('bans_version')
         return new_ban, Message(_('New Ban has been set.'), 'success')
         return new_ban, Message(_('New Ban has been set.'), 'success')
 
 
 
 
@@ -126,7 +129,8 @@ class Edit(FormWidget):
         target.reason_admin = form.cleaned_data['reason_admin']
         target.reason_admin = form.cleaned_data['reason_admin']
         target.expires = form.cleaned_data['expires']
         target.expires = form.cleaned_data['expires']
         target.save(force_update=True)
         target.save(force_update=True)
-        self.request.monitor.increase('bans_version')
+        with UpdatingMonitor() as cm:
+            monitor.increase('bans_version')
         return target, Message(_('Changes in ban have been saved.'), 'success')
         return target, Message(_('Changes in ban have been saved.'), 'success')
 
 
 
 
@@ -141,7 +145,8 @@ class Delete(ButtonWidget):
 
 
     def action(self, target):
     def action(self, target):
         target.delete()
         target.delete()
-        self.request.monitor.increase('bans_version')
+        with UpdatingMonitor() as cm:
+            monitor.increase('bans_version')
         if target.test == 0:
         if target.test == 0:
             return Message(_('E-mail and username Ban "%(ban)s" has been lifted.') % {'ban': target.ban}, 'success'), False
             return Message(_('E-mail and username Ban "%(ban)s" has been lifted.') % {'ban': target.ban}, 'success'), False
         if target.test == 1:
         if target.test == 1:

+ 7 - 3
misago/apps/admin/forumroles/views.py

@@ -6,6 +6,7 @@ from misago.admin import site
 from misago.apps.admin.widgets import *
 from misago.apps.admin.widgets import *
 from misago.forms import Form, YesNoSwitch
 from misago.forms import Form, YesNoSwitch
 from misago.models import ForumRole
 from misago.models import ForumRole
+from misago.monitor import monitor, UpdatingMonitor
 from misago.utils.strings import slugify
 from misago.utils.strings import slugify
 from misago.apps.admin.forumroles.forms import ForumRoleForm
 from misago.apps.admin.forumroles.forms import ForumRoleForm
 
 
@@ -40,7 +41,8 @@ class List(ListWidget):
                 )
                 )
 
 
     def action_delete(self, items, checked):
     def action_delete(self, items, checked):
-        self.request.monitor.increase('acl_version')
+        with UpdatingMonitor() as cm:
+            monitor.increase('acl_version')
         Role.objects.filter(id__in=checked).delete()
         Role.objects.filter(id__in=checked).delete()
         return Message(_('Selected forum roles have been deleted successfully.'), 'success'), reverse('admin_roles_forums')
         return Message(_('Selected forum roles have been deleted successfully.'), 'success'), reverse('admin_roles_forums')
 
 
@@ -127,7 +129,8 @@ class ACL(FormWidget):
             raw_acl[perm] = form.cleaned_data[perm]
             raw_acl[perm] = form.cleaned_data[perm]
         target.permissions = raw_acl
         target.permissions = raw_acl
         target.save(force_update=True)
         target.save(force_update=True)
-        self.request.monitor.increase('acl_version')
+        with UpdatingMonitor() as cm:
+            monitor.increase('acl_version')
 
 
         return target, Message(_('Forum Role "%(name)s" permissions have been changed.') % {'name': self.original_name}, 'success')
         return target, Message(_('Forum Role "%(name)s" permissions have been changed.') % {'name': self.original_name}, 'success')
 
 
@@ -140,5 +143,6 @@ class Delete(ButtonWidget):
 
 
     def action(self, target):
     def action(self, target):
         target.delete()
         target.delete()
-        self.request.monitor.increase('acl_version')
+        with UpdatingMonitor() as cm:
+            monitor.increase('acl_version')
         return Message(_('Forum Role "%(name)s" has been deleted.') % {'name': _(target.name)}, 'success'), False
         return Message(_('Forum Role "%(name)s" has been deleted.') % {'name': _(target.name)}, 'success'), False

+ 12 - 8
misago/apps/admin/forums/views.py

@@ -9,6 +9,7 @@ from mptt.forms import TreeNodeChoiceField
 from misago.admin import site
 from misago.admin import site
 from misago.apps.admin.widgets import *
 from misago.apps.admin.widgets import *
 from misago.models import Forum
 from misago.models import Forum
+from misago.monitor import monitor, UpdatingMonitor
 from misago.shortcuts import render_to_response
 from misago.shortcuts import render_to_response
 from misago.utils.strings import slugify
 from misago.utils.strings import slugify
 from misago.apps.admin.forums.forms import NewNodeForm, CategoryForm, ForumForm, RedirectForm, DeleteForm
 from misago.apps.admin.forums.forms import NewNodeForm, CategoryForm, ForumForm, RedirectForm, DeleteForm
@@ -189,7 +190,8 @@ class NewNode(FormWidget):
 
 
         if form.cleaned_data['perms']:
         if form.cleaned_data['perms']:
             new_forum.copy_permissions(form.cleaned_data['perms'])
             new_forum.copy_permissions(form.cleaned_data['perms'])
-            self.request.monitor.increase('acl_version')
+            with UpdatingMonitor() as cm:
+                monitor.increase('acl_version')
 
 
         self.request.session['forums_admin_preffs'] = {
         self.request.session['forums_admin_preffs'] = {
             'parent': form.cleaned_data['parent'].pk,
             'parent': form.cleaned_data['parent'].pk,
@@ -304,19 +306,20 @@ class Edit(FormWidget):
             target.prune_last = form.cleaned_data['prune_last']
             target.prune_last = form.cleaned_data['prune_last']
             target.pruned_archive = form.cleaned_data['pruned_archive']
             target.pruned_archive = form.cleaned_data['pruned_archive']
 
 
-        if form.cleaned_data['parent'].pk != target.parent.pk:
-            target.move_to(form.cleaned_data['parent'], 'last-child')
-            self.request.monitor.increase('acl_version')
-
         target.save(force_update=True)
         target.save(force_update=True)
         Forum.objects.populate_tree(True)
         Forum.objects.populate_tree(True)
 
 
         if form.cleaned_data['perms']:
         if form.cleaned_data['perms']:
             target.copy_permissions(form.cleaned_data['perms'])
             target.copy_permissions(form.cleaned_data['perms'])
 
 
-        if form.cleaned_data['parent'].pk != target.parent.pk or form.cleaned_data['perms']:
-            self.request.monitor.increase('acl_version')
+        with UpdatingMonitor() as cm:
+            if form.cleaned_data['parent'].pk != target.parent.pk:
+                target.move_to(form.cleaned_data['parent'], 'last-child')
+                monitor.increase('acl_version')
 
 
+            if form.cleaned_data['parent'].pk != target.parent.pk or form.cleaned_data['perms']:
+                monitor.increase('acl_version')
+                
         if self.original_name != target.name:
         if self.original_name != target.name:
             target.sync_name()
             target.sync_name()
 
 
@@ -373,5 +376,6 @@ class Delete(FormWidget):
                 Forum.objects.get(id=child.pk).delete()
                 Forum.objects.get(id=child.pk).delete()
         Forum.objects.get(id=target.pk).delete()
         Forum.objects.get(id=target.pk).delete()
         Forum.objects.populate_tree(True)
         Forum.objects.populate_tree(True)
-        self.request.monitor.increase('acl_version')
+        with UpdatingMonitor() as cm:
+            monitor.increase('acl_version')
         return target, Message(_('Forum "%(name)s" has been deleted.') % {'name': self.original_name}, 'success')
         return target, Message(_('Forum "%(name)s" has been deleted.') % {'name': self.original_name}, 'success')

+ 5 - 4
misago/apps/admin/index.py

@@ -1,14 +1,15 @@
 from django.template import RequestContext
 from django.template import RequestContext
 from misago.models import Session
 from misago.models import Session
+from misago.monitor import monitor
 from misago.shortcuts import render_to_response
 from misago.shortcuts import render_to_response
 
 
 def index(request):
 def index(request):
     return render_to_response('index.html',
     return render_to_response('index.html',
                               {
                               {
-                               'users': request.monitor['users'],
-                               'users_inactive': request.monitor['users_inactive'],
-                               'threads': request.monitor['threads'],
-                               'posts': request.monitor['posts'],
+                               'users': monitor.users,
+                               'users_inactive': monitor.users_inactive,
+                               'threads': monitor.threads,
+                               'posts': monitor.posts,
                                'admins': Session.objects.filter(user__isnull=False).filter(admin=1).order_by('user__username_slug').select_related('user'),
                                'admins': Session.objects.filter(user__isnull=False).filter(admin=1).order_by('user__username_slug').select_related('user'),
                               },
                               },
                               context_instance=RequestContext(request));
                               context_instance=RequestContext(request));

+ 1 - 1
misago/apps/admin/pruneusers/views.py

@@ -189,7 +189,7 @@ class Apply(FormWidget):
                                                                  '%(deleted)d users have been deleted.',
                                                                  '%(deleted)d users have been deleted.',
                                                                  deleted
                                                                  deleted
                                                                  ) % {'deleted': deleted}), 'success', self.admin.id)
                                                                  ) % {'deleted': deleted}), 'success', self.admin.id)
-                    User.objects.resync_monitor(request.monitor)
+                    User.objects.resync_monitor()
                 else:
                 else:
                     request.messages.set_flash(Message(_("No users have been deleted.")), 'info', self.admin.id)
                     request.messages.set_flash(Message(_("No users have been deleted.")), 'info', self.admin.id)
                 return redirect(reverse('admin_prune_users'))
                 return redirect(reverse('admin_prune_users'))

+ 5 - 2
misago/apps/admin/roles/views.py

@@ -7,6 +7,7 @@ from misago.admin import site
 from misago.apps.admin.widgets import *
 from misago.apps.admin.widgets import *
 from misago.forms import Form, YesNoSwitch
 from misago.forms import Form, YesNoSwitch
 from misago.models import Forum, ForumRole, Role
 from misago.models import Forum, ForumRole, Role
+from misago.monitor import monitor, UpdatingMonitor
 from misago.utils.strings import slugify
 from misago.utils.strings import slugify
 from misago.apps.admin.roles.forms import RoleForm
 from misago.apps.admin.roles.forms import RoleForm
 
 
@@ -110,7 +111,8 @@ class Edit(FormWidget):
         if self.request.user.is_god():
         if self.request.user.is_god():
             target.protected = form.cleaned_data['protected']
             target.protected = form.cleaned_data['protected']
         target.save(force_update=True)
         target.save(force_update=True)
-        self.request.monitor.increase('acl_version')
+        with UpdatingMonitor() as cm:
+            monitor.increase('acl_version')
         return target, Message(_('Changes in role "%(name)s" have been saved.') % {'name': self.original_name}, 'success')
         return target, Message(_('Changes in role "%(name)s" have been saved.') % {'name': self.original_name}, 'success')
 
 
 
 
@@ -226,7 +228,8 @@ class ACL(FormWidget):
             raw_acl[perm] = form.cleaned_data[perm]
             raw_acl[perm] = form.cleaned_data[perm]
         target.permissions = raw_acl
         target.permissions = raw_acl
         target.save(force_update=True)
         target.save(force_update=True)
-        self.request.monitor.increase('acl_version')
+        with UpdatingMonitor() as cm:
+            monitor.increase('acl_version')
         
         
         return target, Message(_('Role "%(name)s" permissions have been changed.') % {'name': self.original_name}, 'success')
         return target, Message(_('Role "%(name)s" permissions have been changed.') % {'name': self.original_name}, 'success')
 
 

+ 6 - 4
misago/apps/admin/users/views.py

@@ -7,6 +7,7 @@ from misago.apps.admin.widgets import *
 from misago.conf import settings
 from misago.conf import settings
 from misago.markdown import signature_markdown
 from misago.markdown import signature_markdown
 from misago.models import Forum, User
 from misago.models import Forum, User
+from misago.monitor import monitor, UpdatingMonitor
 from misago.utils.strings import random_string
 from misago.utils.strings import random_string
 from misago.apps.admin.users.forms import UserForm, NewUserForm, SearchUsersForm
 from misago.apps.admin.users.forms import UserForm, NewUserForm, SearchUsersForm
 
 
@@ -94,7 +95,8 @@ class List(ListWidget):
     def action_activate(self, items, checked):
     def action_activate(self, items, checked):
         for user in items:
         for user in items:
             if user.pk in checked and user.activation > 0:
             if user.pk in checked and user.activation > 0:
-                self.request.monitor.decrease('users_inactive')
+                with UpdatingMonitor() as cm:
+                    monitor.decrease('users_inactive')
                 user.activation = user.ACTIVATION_NONE
                 user.activation = user.ACTIVATION_NONE
                 user.save(force_update=True)
                 user.save(force_update=True)
                 user.email_user(
                 user.email_user(
@@ -209,7 +211,7 @@ class List(ListWidget):
             forum.sync()
             forum.sync()
             forum.save(force_update=True)
             forum.save(force_update=True)
         
         
-        User.objects.resync_monitor(self.request.monitor)
+        User.objects.resync_monitor()
         return Message(_('Selected users and their content have been deleted successfully.'), 'success'), reverse('admin_users')
         return Message(_('Selected users and their content have been deleted successfully.'), 'success'), reverse('admin_users')
 
 
     def action_delete(self, items, checked):
     def action_delete(self, items, checked):
@@ -224,7 +226,7 @@ class List(ListWidget):
             if user.pk in checked:
             if user.pk in checked:
                 user.delete()
                 user.delete()
 
 
-        User.objects.resync_monitor(self.request.monitor)
+        User.objects.resync_monitor()
         return Message(_('Selected users have been deleted successfully.'), 'success'), reverse('admin_users')
         return Message(_('Selected users have been deleted successfully.'), 'success'), reverse('admin_users')
 
 
 
 
@@ -361,7 +363,7 @@ class Delete(ButtonWidget):
         if target.is_protected():
         if target.is_protected():
             return Message(_('You cannot delete protected member.'), 'error'), False
             return Message(_('You cannot delete protected member.'), 'error'), False
         target.delete()
         target.delete()
-        User.objects.resync_monitor(self.request.monitor)
+        User.objects.resync_monitor()
         return Message(_('User "%(name)s" has been deleted.') % {'name': target.username}, 'success'), False
         return Message(_('User "%(name)s" has been deleted.') % {'name': target.username}, 'success'), False
 
 
 
 

+ 1 - 1
misago/apps/register/views.py

@@ -65,7 +65,7 @@ def form(request):
                                     {'password': form.cleaned_data['password']}
                                     {'password': form.cleaned_data['password']}
                                     )
                                     )
             
             
-            User.objects.resync_monitor(request.monitor)
+            User.objects.resync_monitor()
             return redirect(reverse('index'))
             return redirect(reverse('index'))
         else:
         else:
             message = Message(form.non_field_errors()[0], 'error')
             message = Message(form.non_field_errors()[0], 'error')

+ 4 - 2
misago/apps/reports/list.py

@@ -8,6 +8,7 @@ from misago.apps.threadtype.list import ThreadsListBaseView, ThreadsListModerati
 from misago.conf import settings
 from misago.conf import settings
 from misago.messages import Message
 from misago.messages import Message
 from misago.models import Forum, Thread, Post
 from misago.models import Forum, Thread, Post
+from misago.monitor import monitor, UpdatingMonitor
 from misago.readstrackers import ThreadsTracker
 from misago.readstrackers import ThreadsTracker
 from misago.utils.pagination import make_pagination
 from misago.utils.pagination import make_pagination
 from misago.apps.reports.mixins import TypeMixin
 from misago.apps.reports.mixins import TypeMixin
@@ -48,8 +49,9 @@ class ThreadsListView(ThreadsListBaseView, ThreadsListModeration, TypeMixin):
                 thread.report_forum = Forum.objects.forums_tree.get(thread.report_for.forum_id)
                 thread.report_forum = Forum.objects.forums_tree.get(thread.report_for.forum_id)
             self.threads.append(thread)
             self.threads.append(thread)
 
 
-        if int(self.request.monitor['reported_posts']) != unresolved_count:
-            self.request.monitor['reported_posts'] = unresolved_count
+        if int(monitor.reported_posts) != unresolved_count:
+            with UpdatingMonitor() as cm:
+                monitor.reported_posts = unresolved_count
 
 
     def threads_actions(self):
     def threads_actions(self):
         acl = self.request.acl.threads.get_role(self.forum)
         acl = self.request.acl.threads.get_role(self.forum)

+ 3 - 1
misago/apps/reports/posting.py

@@ -4,6 +4,7 @@ from django.utils.translation import ugettext as _
 from misago.apps.threadtype.posting import EditThreadBaseView, NewReplyBaseView, EditReplyBaseView
 from misago.apps.threadtype.posting import EditThreadBaseView, NewReplyBaseView, EditReplyBaseView
 from misago.messages import Message
 from misago.messages import Message
 from misago.models import Forum, Thread, Post
 from misago.models import Forum, Thread, Post
+from misago.monitor import monitor, UpdatingMonitor
 from misago.apps.reports.mixins import TypeMixin
 from misago.apps.reports.mixins import TypeMixin
 from misago.apps.reports.forms import EditThreadForm, NewReplyForm, EditReplyForm
 from misago.apps.reports.forms import EditThreadForm, NewReplyForm, EditReplyForm
 
 
@@ -13,7 +14,8 @@ class SetStateCheckpointMixin(object):
         super(SetStateCheckpointMixin, self).post_form(form)
         super(SetStateCheckpointMixin, self).post_form(form)
         if self.thread.original_weight != self.thread.weight:
         if self.thread.original_weight != self.thread.weight:
             if self.thread.original_weight == 2:
             if self.thread.original_weight == 2:
-                self.request.monitor.decrease('reported_posts')
+                with UpdatingMonitor() as cm:
+                    monitor.decrease('reported_posts')
             if self.thread.weight == 1:
             if self.thread.weight == 1:
                 self.thread.set_checkpoint(self.request, 'resolved')
                 self.thread.set_checkpoint(self.request, 'resolved')
             if self.thread.weight == 0:
             if self.thread.weight == 0:

+ 9 - 4
misago/apps/reports/thread.py

@@ -2,6 +2,7 @@ from django.utils.translation import ugettext as _
 from misago.apps.threadtype.thread import ThreadBaseView, ThreadModeration, PostsModeration
 from misago.apps.threadtype.thread import ThreadBaseView, ThreadModeration, PostsModeration
 from misago.messages import Message
 from misago.messages import Message
 from misago.models import Forum, Thread
 from misago.models import Forum, Thread
+from misago.monitor import monitor, UpdatingMonitor
 from misago.apps.reports.mixins import TypeMixin
 from misago.apps.reports.mixins import TypeMixin
 
 
 class ThreadView(ThreadBaseView, ThreadModeration, PostsModeration, TypeMixin):
 class ThreadView(ThreadBaseView, ThreadModeration, PostsModeration, TypeMixin):
@@ -45,23 +46,27 @@ class ThreadView(ThreadBaseView, ThreadModeration, PostsModeration, TypeMixin):
     def after_thread_action_sticky(self):
     def after_thread_action_sticky(self):
         self.thread.set_checkpoint(self.request, 'resolved')
         self.thread.set_checkpoint(self.request, 'resolved')
         if self.thread.original_weight == 2:
         if self.thread.original_weight == 2:
-            self.request.monitor.decrease('reported_posts')
+            with UpdatingMonitor() as cm:
+                monitor.decrease('reported_posts')
         self.request.messages.set_flash(Message(_('Report has been set as resolved.')), 'success', 'threads')
         self.request.messages.set_flash(Message(_('Report has been set as resolved.')), 'success', 'threads')
 
 
     def after_thread_action_normal(self):
     def after_thread_action_normal(self):
         self.thread.set_checkpoint(self.request, 'bogus')
         self.thread.set_checkpoint(self.request, 'bogus')
         if self.thread.original_weight == 2:
         if self.thread.original_weight == 2:
-            self.request.monitor.decrease('reported_posts')
+            with UpdatingMonitor() as cm:
+                monitor.decrease('reported_posts')
         self.request.messages.set_flash(Message(_('Report has been set as bogus.')), 'success', 'threads')
         self.request.messages.set_flash(Message(_('Report has been set as bogus.')), 'success', 'threads')
 
 
     def after_thread_action_undelete(self):
     def after_thread_action_undelete(self):
         if self.thread.original_weight == 2:
         if self.thread.original_weight == 2:
-            self.request.monitor.increase('reported_posts')
+            with UpdatingMonitor() as cm:
+                monitor.increase('reported_posts')
         self.request.messages.set_flash(Message(_('Report has been restored.')), 'success', 'threads')
         self.request.messages.set_flash(Message(_('Report has been restored.')), 'success', 'threads')
 
 
     def after_thread_action_soft(self):
     def after_thread_action_soft(self):
         if self.thread.original_weight == 2:
         if self.thread.original_weight == 2:
-            self.request.monitor.decrease('reported_posts')
+            with UpdatingMonitor() as cm:
+                monitor.decrease('reported_posts')
         self.request.messages.set_flash(Message(_('Report has been hidden.')), 'success', 'threads')
         self.request.messages.set_flash(Message(_('Report has been hidden.')), 'success', 'threads')
 
 
     def after_thread_action_hard(self):
     def after_thread_action_hard(self):

+ 3 - 1
misago/apps/threadtype/jumps.py

@@ -9,6 +9,7 @@ from misago.decorators import block_guest, check_csrf
 from misago.markdown import post_markdown
 from misago.markdown import post_markdown
 from misago.messages import Message
 from misago.messages import Message
 from misago.models import Forum, Checkpoint, Thread, Post, Karma, WatchedThread
 from misago.models import Forum, Checkpoint, Thread, Post, Karma, WatchedThread
+from misago.monitor import monitor, UpdatingMonitor
 from misago.readstrackers import ThreadsTracker
 from misago.readstrackers import ThreadsTracker
 from misago.utils.strings import short_string, slugify
 from misago.utils.strings import short_string, slugify
 from misago.utils.views import json_response
 from misago.utils.views import json_response
@@ -331,7 +332,8 @@ Member @%(reporter)s has reported following post by @%(reported)s:
                 self.post.save(force_update=True)
                 self.post.save(force_update=True)
                 self.thread.replies_reported += 1
                 self.thread.replies_reported += 1
                 self.thread.save(force_update=True)
                 self.thread.save(force_update=True)
-                request.monitor.increase('reported_posts')
+                with UpdatingMonitor() as cm:
+                    monitor.increase('reported_posts')
                 made_report = True
                 made_report = True
 
 
             if made_report:
             if made_report:

+ 4 - 2
misago/apps/threadtype/list/moderation.py

@@ -5,6 +5,7 @@ from django.utils.translation import ugettext as _
 from misago.forms import FormLayout
 from misago.forms import FormLayout
 from misago.messages import Message
 from misago.messages import Message
 from misago.models import Forum, Thread, Post
 from misago.models import Forum, Thread, Post
+from misago.monitor import monitor, UpdatingMonitor
 from misago.shortcuts import render_to_response
 from misago.shortcuts import render_to_response
 from misago.apps.threadtype.list.forms import MoveThreadsForm, MergeThreadsForm
 from misago.apps.threadtype.list.forms import MoveThreadsForm, MergeThreadsForm
 from misago.utils.strings import slugify
 from misago.utils.strings import slugify
@@ -36,8 +37,9 @@ class ThreadsListModeration(object):
                     thread.start_post.user.posts += 1
                     thread.start_post.user.posts += 1
                     users.append(thread.start_post.user)
                     users.append(thread.start_post.user)
         if accepted:
         if accepted:
-            self.request.monitor['threads'] = int(self.request.monitor['threads']) + accepted
-            self.request.monitor['posts'] = int(self.request.monitor['posts']) + accepted
+            with UpdatingMonitor() as cm:
+                monitor.threads = int(monitor.threads) + accepted
+                monitor.posts = int(monitor.posts) + accepted
             self.forum.sync()
             self.forum.sync()
             self.forum.save(force_update=True)
             self.forum.save(force_update=True)
             for user in users:
             for user in users:

+ 3 - 1
misago/apps/threadtype/posting/newreply.py

@@ -4,6 +4,7 @@ from django.utils.translation import ugettext as _
 from misago.conf import settings
 from misago.conf import settings
 from misago.markdown import post_markdown
 from misago.markdown import post_markdown
 from misago.models import Post
 from misago.models import Post
+from misago.monitor import monitor, UpdatingMonitor
 from misago.utils.datesformats import date
 from misago.utils.datesformats import date
 from misago.utils.translation import ugettext_lazy
 from misago.utils.translation import ugettext_lazy
 from misago.apps.threadtype.posting.base import PostingBaseView
 from misago.apps.threadtype.posting.base import PostingBaseView
@@ -79,7 +80,8 @@ class NewReplyBaseView(PostingBaseView):
 
 
         # Update forum and monitor
         # Update forum and monitor
         if not moderation and not merged:
         if not moderation and not merged:
-            self.request.monitor.increase('posts')
+            with UpdatingMonitor() as cm:
+                monitor.increase('posts')
             self.forum.posts += 1
             self.forum.posts += 1
             self.forum.new_last_thread(self.thread)
             self.forum.new_last_thread(self.thread)
             self.forum.save(force_update=True)
             self.forum.save(force_update=True)

+ 4 - 2
misago/apps/threadtype/posting/newthread.py

@@ -5,6 +5,7 @@ from misago.apps.threadtype.posting.forms import NewThreadForm
 from misago.conf import settings
 from misago.conf import settings
 from misago.markdown import post_markdown
 from misago.markdown import post_markdown
 from misago.models import Forum, Thread, Post
 from misago.models import Forum, Thread, Post
+from misago.monitor import monitor, UpdatingMonitor
 from misago.utils.strings import slugify
 from misago.utils.strings import slugify
 
 
 class NewThreadBaseView(PostingBaseView):
 class NewThreadBaseView(PostingBaseView):
@@ -63,8 +64,9 @@ class NewThreadBaseView(PostingBaseView):
 
 
         # Update forum monitor
         # Update forum monitor
         if not moderation:
         if not moderation:
-            self.request.monitor.increase('threads')
-            self.request.monitor.increase('posts')
+            with UpdatingMonitor() as cm:
+                monitor.increase('threads')
+                monitor.increase('posts')
             self.forum.threads += 1
             self.forum.threads += 1
             self.forum.posts += 1
             self.forum.posts += 1
             self.forum.new_last_thread(self.thread)
             self.forum.new_last_thread(self.thread)

+ 13 - 8
misago/apps/threadtype/thread/moderation/thread.py

@@ -2,6 +2,7 @@ from django.template import RequestContext
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
 from misago.forms import Form, FormLayout
 from misago.forms import Form, FormLayout
 from misago.messages import Message
 from misago.messages import Message
+from misago.monitor import monitor, UpdatingMonitor
 from misago.shortcuts import render_to_response
 from misago.shortcuts import render_to_response
 from misago.apps.threadtype.list.forms import MoveThreadsForm
 from misago.apps.threadtype.list.forms import MoveThreadsForm
 
 
@@ -23,8 +24,9 @@ class ThreadModeration(object):
         self.forum.sync()
         self.forum.sync()
         self.forum.save(force_update=True)
         self.forum.save(force_update=True)
         # Update monitor
         # Update monitor
-        self.request.monitor.increase('threads')
-        self.request.monitor.increase('posts', self.thread.replies + 1)
+        with UpdatingMonitor() as cm:
+            monitor.increase('threads')
+            monitor.increase('posts', self.thread.replies + 1)
         # After
         # After
         self.after_thread_action_accept()
         self.after_thread_action_accept()
 
 
@@ -115,8 +117,9 @@ class ThreadModeration(object):
         self.forum.sync()
         self.forum.sync()
         self.forum.save(force_update=True)
         self.forum.save(force_update=True)
         # Update monitor
         # Update monitor
-        self.request.monitor.increase('threads')
-        self.request.monitor.increase('posts', self.thread.replies + 1)
+        with UpdatingMonitor() as cm:
+            monitor.increase('threads')
+            monitor.increase('posts', self.thread.replies + 1)
         self.after_thread_action_undelete()
         self.after_thread_action_undelete()
 
 
     def after_thread_action_undelete(self):
     def after_thread_action_undelete(self):
@@ -135,8 +138,9 @@ class ThreadModeration(object):
         self.forum.sync()
         self.forum.sync()
         self.forum.save(force_update=True)
         self.forum.save(force_update=True)
         # Update monitor
         # Update monitor
-        self.request.monitor.decrease('threads')
-        self.request.monitor.decrease('posts', self.thread.replies + 1)
+        with UpdatingMonitor() as cm:
+            monitor.decrease('threads')
+            monitor.decrease('posts', self.thread.replies + 1)
         self.after_thread_action_soft()
         self.after_thread_action_soft()
 
 
     def after_thread_action_soft(self):
     def after_thread_action_soft(self):
@@ -149,8 +153,9 @@ class ThreadModeration(object):
         self.forum.sync()
         self.forum.sync()
         self.forum.save(force_update=True)
         self.forum.save(force_update=True)
         # Update monitor
         # Update monitor
-        self.request.monitor.decrease('threads')
-        self.request.monitor.decrease('posts', self.thread.replies + 1)
+        with UpdatingMonitor() as cm:
+            monitor.decrease('threads')
+            monitor.decrease('posts', self.thread.replies + 1)
         self.after_thread_action_hard()
         self.after_thread_action_hard()
         return self.threads_list_redirect()
         return self.threads_list_redirect()
 
 

+ 4 - 4
misago/conf.py

@@ -3,7 +3,7 @@ from django.core.cache import cache
 from misago.models import Setting
 from misago.models import Setting
 from misago.thread import local
 from misago.thread import local
 
 
-_local_thread = local()
+_thread_local = local()
 
 
 def load_settings():
 def load_settings():
     settings = cache.get('settings', {})
     settings = cache.get('settings', {})
@@ -42,7 +42,7 @@ class MisagoSettings(object):
         return self.setting(key)
         return self.setting(key)
 
 
     def __contains__(self, key):
     def __contains__(self, key):
-        return key in self.settings
+        return key in self.settings()
 
 
     def __getitem__(self, key):
     def __getitem__(self, key):
         return self.setting(key)
         return self.setting(key)
@@ -53,11 +53,11 @@ class MisagoSettings(object):
         setting.save(force_update=True)
         setting.save(force_update=True)
 
 
 
 
-settings = MisagoSettings(_local_thread, True)
+settings = MisagoSettings(_thread_local, True)
 
 
 
 
 def SafeSettings(): 
 def SafeSettings(): 
     """
     """
     Safe settings factory for MisagoSettings
     Safe settings factory for MisagoSettings
     """
     """
-    return MisagoSettings(_local_thread, False)
+    return MisagoSettings(_thread_local, False)

+ 3 - 2
misago/context_processors.py

@@ -1,7 +1,8 @@
-from misago.conf import settings, SafeSettings
 from misago import __version__
 from misago import __version__
 from misago.admin import site
 from misago.admin import site
+from misago.conf import settings, SafeSettings
 from misago.models import Forum
 from misago.models import Forum
+from misago.monitor import monitor
 
 
 def common(request):
 def common(request):
     context = {
     context = {
@@ -26,7 +27,7 @@ def common(request):
             'acl': request.acl,
             'acl': request.acl,
             'board_address': settings.BOARD_ADDRESS,
             'board_address': settings.BOARD_ADDRESS,
             'messages' : request.messages.messages,
             'messages' : request.messages.messages,
-            'monitor': request.monitor,
+            'monitor': monitor,
             'request_path': request.get_full_path(),
             'request_path': request.get_full_path(),
             'settings': SafeSettings(),
             'settings': SafeSettings(),
             'stopwatch': request.stopwatch.time(),
             'stopwatch': request.stopwatch.time(),

+ 1 - 2
misago/management/commands/syncusermonitor.py

@@ -1,12 +1,11 @@
 from django.core.management.base import BaseCommand
 from django.core.management.base import BaseCommand
 from django.utils import timezone
 from django.utils import timezone
 from optparse import make_option
 from optparse import make_option
-from misago.monitor import Monitor
 from misago.models import User
 from misago.models import User
 
 
 class Command(BaseCommand):
 class Command(BaseCommand):
     help = 'Updates forum monitor to contain to date user information'
     help = 'Updates forum monitor to contain to date user information'
 
 
     def handle(self, *args, **options):
     def handle(self, *args, **options):
-        User.objects.resync_monitor(Monitor())
+        User.objects.resync_monitor()
         self.stdout.write('\nForum monitor has been updated to contain to date user information.\n')
         self.stdout.write('\nForum monitor has been updated to contain to date user information.\n')

+ 0 - 5
misago/middleware/monitor.py

@@ -1,5 +0,0 @@
-from misago.monitor import Monitor
-
-class MonitorMiddleware(object):
-    def process_request(self, request):
-        request.monitor = Monitor()

+ 2 - 1
misago/middleware/user.py

@@ -2,6 +2,7 @@ from django.utils import timezone
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
 from misago.conf import settings
 from misago.conf import settings
 from misago.messages import Message
 from misago.messages import Message
+from misago.monitor import monitor, UpdatingMonitor
 from misago.onlines import MembersOnline
 from misago.onlines import MembersOnline
 
 
 def set_timezone(new_tz):
 def set_timezone(new_tz):
@@ -23,7 +24,7 @@ class UserMiddleware(object):
         else:
         else:
             set_timezone(settings.default_timezone)
             set_timezone(settings.default_timezone)
             request.session.rank = None
             request.session.rank = None
-        request.onlines = MembersOnline(settings.online_counting, request.monitor, settings.online_counting_frequency)
+        request.onlines = MembersOnline(settings.online_counting, settings.online_counting_frequency)
 
 
     def process_response(self, request, response):
     def process_response(self, request, response):
         try:
         try:

+ 4 - 3
misago/models/banmodel.py

@@ -2,6 +2,7 @@ import re
 from django.db import models
 from django.db import models
 from django.db.models import Q
 from django.db.models import Q
 from django.utils import timezone
 from django.utils import timezone
+from misago.monitor import monitor
 
 
 BAN_NAME_EMAIL = 0
 BAN_NAME_EMAIL = 0
 BAN_NAME = 1
 BAN_NAME = 1
@@ -58,9 +59,9 @@ class BanCache(object):
         self.version = 0
         self.version = 0
 
 
     def check_for_updates(self, request):
     def check_for_updates(self, request):
-        if (self.version < request.monitor['bans_version']
-            or (self.expires != None and self.expires < timezone.now())):
-            self.version = request.monitor['bans_version']
+        if (self.version < monitor.bans_version
+                or (self.expires != None and self.expires < timezone.now())):
+            self.version = monitor.bans_version
 
 
             # Check Ban
             # Check Ban
             if request.user.is_authenticated():
             if request.user.is_authenticated():

+ 17 - 21
misago/models/usermodel.py

@@ -14,6 +14,7 @@ from django.utils import timezone as tz_util
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
 from misago.acl.builder import acl
 from misago.acl.builder import acl
 from misago.conf import settings
 from misago.conf import settings
+from misago.monitor import monitor, UpdatingMonitor
 from misago.signals import delete_user_content, rename_user, sync_user_profile
 from misago.signals import delete_user_content, rename_user, sync_user_profile
 from misago.template.loader import render_to_string
 from misago.template.loader import render_to_string
 from misago.utils.avatars import avatar_size
 from misago.utils.avatars import avatar_size
@@ -31,13 +32,14 @@ class UserManager(models.Manager):
                         )
                         )
         return blank_user
         return blank_user
 
 
-    def resync_monitor(self, monitor):
-        monitor['users'] = self.filter(activation=0).count()
-        monitor['users_inactive'] = self.filter(activation__gt=0).count()
-        last_user = self.filter(activation=0).latest('id')
-        monitor['last_user'] = last_user.pk
-        monitor['last_user_name'] = last_user.username
-        monitor['last_user_slug'] = last_user.username_slug
+    def resync_monitor(self):
+        with UpdatingMonitor() as cm:
+            monitor.users = self.filter(activation=0).count()
+            monitor.users_inactive = self.filter(activation__gt=0).count()
+            last_user = self.filter(activation=0).latest('id')
+            monitor.last_user = last_user.pk
+            monitor.last_user_name = last_user.username
+            monitor.last_user_slug = last_user.username_slug
 
 
     def create_user(self, username, email, password, timezone=False, ip='127.0.0.1', agent='', no_roles=False, activation=0, request=False):
     def create_user(self, username, email, password, timezone=False, ip='127.0.0.1', agent='', no_roles=False, activation=0, request=False):
         token = ''
         token = ''
@@ -83,21 +85,15 @@ class UserManager(models.Manager):
             new_user.make_acl_key()
             new_user.make_acl_key()
             new_user.save(force_update=True)
             new_user.save(force_update=True)
 
 
-        # Load monitor
-        try:
-            monitor = request.monitor
-        except AttributeError:
-            from misago.monitor import Monitor
-            monitor = Monitor()
-
         # Update forum stats
         # Update forum stats
-        if activation == 0:
-            monitor.increase('users')
-            monitor['last_user'] = new_user.pk
-            monitor['last_user_name'] = new_user.username
-            monitor['last_user_slug'] = new_user.username_slug
-        else:
-            monitor.increase('users_inactive')
+        with UpdatingMonitor() as cm:
+            if activation == 0:
+                monitor.increase('users')
+                monitor.last_user = new_user.pk
+                monitor.last_user_name = new_user.username
+                monitor.last_user_slug = new_user.username_slug
+            else:
+                monitor.increase('users_inactive')
 
 
         # Return new user
         # Return new user
         return new_user
         return new_user

+ 64 - 42
misago/monitor.py

@@ -1,80 +1,102 @@
 from datetime import timedelta
 from datetime import timedelta
 from django.core.cache import cache
 from django.core.cache import cache
 from django.utils import timezone
 from django.utils import timezone
-from misago.models import MonitorItem
+from misago.thread import local
+
+_thread_local = local()
+
+def load_monitor():
+    from misago.models import MonitorItem
+    monitor = cache.get('monitor', {})
+    if not monitor:
+        for i in MonitorItem.objects.all():
+            monitor[i.id] = [i.value, i.updated, i.type]
+        cache.set('monitor', monitor)
+    return monitor
+
 
 
 class Monitor(object):
 class Monitor(object):
-    def __init__(self):
-        self._cache_deleted = False
-        self._items = {}
-        self.refresh()
-
-    def refresh(self):
-        self._items = cache.get('monitor')
-        if not self._items:
-            self._items = {}
-            for i in MonitorItem.objects.all():
-                self._items[i.id] = [i.value, i.updated, i.type]
-            cache.set('monitor', self._items)
+    def __init__(self, local):
+        self.thread = local
+
+    def monitor(self):
+        try:
+            return self.thread.monitor
+        except AttributeError:
+            self.thread.monitor = load_monitor()
+            return self.thread.monitor
+
+    def entry(self, key):
+        try:
+            return self.monitor()[key]
+        except KeyError:
+            raise Exception(u"Monitor entry \"%s\" could not be found." % key)
 
 
     def __contains__(self, key):
     def __contains__(self, key):
-        return key in self._items
+        return key in self.monitor()
+
+    def __getattr__(self, key):
+        return self.entry(key)[0]
 
 
     def __getitem__(self, key):
     def __getitem__(self, key):
-        return self._items[key][0]
+        return self.entry(key)[0]
 
 
     def __setitem__(self, key, value):
     def __setitem__(self, key, value):
-        self._items[key][0] = value
-        self._items[key][1] = timezone.now()
-        cache.set('monitor', self._items)
-        sync_item = MonitorItem(
-                                id=key,
-                                value=value,
-                                type=self._items[key][2],
-                                updated=timezone.now()
-                                )
-        sync_item.save(force_update=True)
+        self.thread.monitor_update.append((key, value))
         return value
         return value
 
 
-    def __delitem__(self, key):
-        pass
-
     def increase(self, key, i=1):
     def increase(self, key, i=1):
-        self[key] = self[key] + i
+        self.thread.monitor_update.append((key, self[key] + i))
 
 
     def decrease(self, key, i=1):
     def decrease(self, key, i=1):
-        self[key] = self[key] - i
+        self.thread.monitor_update.append((key, self[key] - i))
 
 
     def get(self, key, default=None):
     def get(self, key, default=None):
-        if not key in self._items:
+        if not key in self.monitor():
             return default
             return default
-        return self._items[key][0]
+        return self.entry(key)[0]
 
 
     def get_updated(self, key):
     def get_updated(self, key):
-        if key in self._items:
-            return self._items[key][1]
+        if key in self.monitor():
+            return self.entry(key)[1]
         return None
         return None
 
 
     def expired(self, key, seconds=5):
     def expired(self, key, seconds=5):
-        return self._items[key][1] < (timezone.now() - timedelta(seconds=seconds))
+        return self.entry(key)[1] < (timezone.now() - timedelta(seconds=seconds))
 
 
     def has_key(self, key):
     def has_key(self, key):
-        return key in self._items
+        return key in self.entry()
 
 
     def keys(self):
     def keys(self):
-        return self._items.keys()
+        return self.entry().keys()
 
 
     def values(self):
     def values(self):
-        return self._items.values()
+        return self.entry().values()
 
 
     def items(self):
     def items(self):
-        return self._items.items()
+        return self.entry().items()
 
 
     def iterkeys(self):
     def iterkeys(self):
-        return self._items.iterkeys()
+        return self.entry().iterkeys()
 
 
     def itervalues(self):
     def itervalues(self):
-        return self._items.itervalues()
+        return self.entry().itervalues()
 
 
     def iteritems(self):
     def iteritems(self):
-        return self._items.iteritems()
+        return self.entry().iteritems()
+
+
+class UpdatingMonitor(object):
+    def __enter__(self):
+        _thread_local.monitor_update = []
+
+    def __exit__(self, type, value, traceback):
+        if _thread_local.monitor_update:
+            from misago.models import MonitorItem
+            for key, value in _thread_local.monitor_update:
+                MonitorItem.objects.filter(pk=key).update(_value=value, updated=timezone.now())
+            cache.delete('monitor')
+            _thread_local.monitor_update = None
+
+
+monitor = Monitor(_thread_local)

+ 9 - 8
misago/onlines.py

@@ -2,14 +2,14 @@ from datetime import timedelta
 from django.core.cache import cache
 from django.core.cache import cache
 from django.utils import timezone
 from django.utils import timezone
 from misago.models import Session
 from misago.models import Session
+from misago.monitor import monitor, UpdatingMonitor
 
 
 class MembersOnline(object):
 class MembersOnline(object):
-    def __init__(self, mode, monitor, frequency=180):
-        self.monitor = monitor
+    def __init__(self, mode, frequency=180):
         self.frequency = frequency
         self.frequency = frequency
         self._mode = mode
         self._mode = mode
-        self._members = int(monitor['online_members'])
-        self._all = int(monitor['online_all'])
+        self._members = int(monitor.online_members)
+        self._all = int(monitor.online_all)
         self._om = self._members
         self._om = self._members
         self._oa = self._all
         self._oa = self._all
         if (self._mode != 'no' or monitor.expired('online_all', frequency) or
         if (self._mode != 'no' or monitor.expired('online_all', frequency) or
@@ -42,10 +42,11 @@ class MembersOnline(object):
 
 
     def sync(self):
     def sync(self):
         if self._mode == 'snap':
         if self._mode == 'snap':
-            if self._members != self._om:
-                self.monitor['online_members'] = self._members
-            if self._all != self._oa:
-                self.monitor['online_all'] = self._all
+            with UpdatingMonitor() as cm:
+                if self._members != self._om:
+                    monitor.online_members = self._members
+                if self._all != self._oa:
+                    monitor.online_all = self._all
 
 
     def stats(self, request):
     def stats(self, request):
         stat = {
         stat = {

+ 0 - 1
misago/settings_base.py

@@ -110,7 +110,6 @@ MIDDLEWARE_CLASSES = (
     'misago.middleware.heartbeat.HeartbeatMiddleware',
     'misago.middleware.heartbeat.HeartbeatMiddleware',
     'debug_toolbar.middleware.DebugToolbarMiddleware',
     'debug_toolbar.middleware.DebugToolbarMiddleware',
     'misago.middleware.cookiejar.CookieJarMiddleware',
     'misago.middleware.cookiejar.CookieJarMiddleware',
-    'misago.middleware.monitor.MonitorMiddleware',
     'misago.middleware.theme.ThemeMiddleware',
     'misago.middleware.theme.ThemeMiddleware',
     'misago.middleware.firewalls.FirewallMiddleware',
     'misago.middleware.firewalls.FirewallMiddleware',
     'misago.middleware.crawlers.DetectCrawlerMiddleware',
     'misago.middleware.crawlers.DetectCrawlerMiddleware',

+ 1 - 1
misago/template/loader.py

@@ -3,6 +3,6 @@ from misago.template.middlewares import process_context
 from misago.template.theme import prefix_templates
 from misago.template.theme import prefix_templates
 
 
 def render_to_string(template_name, dictionary=None, context_instance=None):
 def render_to_string(template_name, dictionary=None, context_instance=None):
-    dictionary = process_context(template_name, dictionary, kwargs.get('context_instance'))
+    dictionary = process_context(template_name, dictionary, context_instance)
     template_name = prefix_templates(template_name)
     template_name = prefix_templates(template_name)
     return django_render_to_string(template_name, dictionary)
     return django_render_to_string(template_name, dictionary)