diff options
-rw-r--r-- | apps/amo/decorators.py | 10 | ||||
-rw-r--r-- | apps/amo/models.py | 35 | ||||
-rw-r--r-- | apps/bandwagon/views.py | 14 |
3 files changed, 56 insertions, 3 deletions
diff --git a/apps/amo/decorators.py b/apps/amo/decorators.py index 18bfc71..a1a7f6c 100644 --- a/apps/amo/decorators.py +++ b/apps/amo/decorators.py @@ -1,3 +1,4 @@ +import contextlib import functools import json @@ -5,6 +6,7 @@ from django import http from django.contrib.auth import decorators as auth_decorators from django.utils.http import urlquote +from .models import use_master, skip_cache from .urlresolvers import reverse @@ -58,3 +60,11 @@ def json_view(f): json_view.error = lambda s: http.HttpResponseBadRequest( json.dumps(s), content_type='application/json') + + +def write(f): + @functools.wraps(f) + def wrapper(*args, **kw): + with contextlib.nested(use_master(), skip_cache()): + return f(*args, **kw) + return wrapper diff --git a/apps/amo/models.py b/apps/amo/models.py index b3cf400..20ea968 100644 --- a/apps/amo/models.py +++ b/apps/amo/models.py @@ -1,14 +1,42 @@ +import contextlib +import threading + from django.db import models from django.utils import translation -import queryset_transform import caching.base +import multidb.pinning +import queryset_transform from translations import transformer from . import signals +_locals = threading.local() +_locals.skip_cache = False + + +@contextlib.contextmanager +def use_master(): + """Within this context, all queries go to the master.""" + multidb.pinning.pin_this_thread() + try: + yield + finally: + multidb.pinning.unpin_this_thread() + + +@contextlib.contextmanager +def skip_cache(): + """Within this context, no queries come from cache.""" + _locals.skip_cache = True + try: + yield + finally: + _locals.skip_cache = False + + class TransformQuerySet(queryset_transform.TransformQuerySet): def pop_transforms(self): @@ -57,7 +85,8 @@ CachingQuerySet.__bases__ = (TransformQuerySet,) + CachingQuerySet.__bases__ class UncachedManagerBase(models.Manager): def get_query_set(self): - return self._with_translations(TransformQuerySet(self.model)) + qs = self._with_translations(TransformQuerySet(self.model)) + return qs def _with_translations(self, qs): # Since we're attaching translations to the object, we need to stick @@ -88,6 +117,8 @@ class ManagerBase(caching.base.CachingManager, UncachedManagerBase): def get_query_set(self): qs = super(ManagerBase, self).get_query_set() + if getattr(_locals, 'skip_cache', False): + qs = qs.no_cache() return self._with_translations(qs) def raw(self, raw_query, params=None, *args, **kwargs): diff --git a/apps/bandwagon/views.py b/apps/bandwagon/views.py index 9ee0402..88eb744 100644 --- a/apps/bandwagon/views.py +++ b/apps/bandwagon/views.py @@ -12,7 +12,7 @@ from tower import ugettext_lazy as _lazy, ugettext as _ from amo import messages import amo.utils import sharing.views -from amo.decorators import login_required, post_required, json_view +from amo.decorators import login_required, post_required, json_view, write from amo.urlresolvers import reverse from access import acl from addons.models import Addon @@ -203,6 +203,7 @@ def get_notes(collection, raw=False): yield rv +@write @login_required def collection_vote(request, username, slug, direction): c = get_collection(request, username, slug) @@ -234,6 +235,7 @@ def initial_data_from_request(request): return dict(author=request.amo_user, application_id=request.APP.id) +@write @login_required def add(request): "Displays/processes a form to create a collection." @@ -266,6 +268,8 @@ def add(request): return render(request, 'bandwagon/add.html', data) +@write +@login_required def ajax_new(request): form = forms.CollectionForm(request.POST or None, initial={'author': request.amo_user, @@ -305,6 +309,7 @@ def ajax_list(request): {'collections': collections}) +@write @login_required @post_required def collection_alter(request, username, slug, action): @@ -332,6 +337,7 @@ def change_addon(request, collection, action): return redirect(url) +@write @login_required @post_required def ajax_collection_alter(request, action): @@ -342,6 +348,7 @@ def ajax_collection_alter(request, action): return change_addon(request, c, action) +@write @login_required @owner_required(require_owner=False) def edit(request, collection, username, slug): @@ -393,6 +400,7 @@ def edit(request, collection, username, slug): return render(request, 'bandwagon/edit.html', data) +@write @login_required @owner_required(require_owner=False) @post_required @@ -407,6 +415,7 @@ def edit_addons(request, collection, username, slug): return http.HttpResponseRedirect(collection.edit_url() + '#addons-edit') +@write @login_required @owner_required @post_required @@ -429,6 +438,7 @@ def edit_contributors(request, collection, username, slug): return http.HttpResponseRedirect(collection.edit_url() + '#users-edit') +@write @login_required @owner_required @post_required @@ -440,6 +450,7 @@ def edit_privacy(request, collection, username, slug): return redirect(collection.get_url_path()) +@write @login_required def delete(request, username, slug): collection = get_object_or_404(Collection, author__username=username, @@ -465,6 +476,7 @@ def delete(request, username, slug): return render(request, 'bandwagon/delete.html', data) +@write @login_required @post_required @json_view |