Родитель
f2ca175e59
Коммит
ceae9d4fd0
|
@ -71,8 +71,6 @@ WORKDIR /data/olympia
|
|||
# Install all python requires
|
||||
RUN pip install --no-cache-dir --exists-action=w --no-deps -r requirements/system.txt \
|
||||
&& pip install --no-cache-dir --exists-action=w --no-deps -r requirements/prod.txt \
|
||||
&& [ -f requirements/prod_without_hash.txt ] \
|
||||
&& pip install --no-cache-dir --exists-action=w --no-deps -r requirements/prod_without_hash.txt\
|
||||
&& pip install --no-cache-dir --exists-action=w --no-deps -e .
|
||||
|
||||
# Link /usr/sbin/uwsgi and /usr/bin/uwsgi to deal with migration from Centos -> Debian
|
||||
|
|
|
@ -101,7 +101,6 @@ install_python_common_dependencies:
|
|||
# Can't use --progress-bar=off for system packages as long as our docker image
|
||||
# doesn't have pip 10 by default.
|
||||
pip install --no-deps --exists-action=w -r requirements/system.txt
|
||||
pip install --progress-bar=off --no-deps --exists-action=w -r requirements/prod_without_hash.txt
|
||||
|
||||
install_python_test_dependencies: install_python_common_dependencies
|
||||
pip install --progress-bar=off --no-deps --exists-action=w -r requirements/tests.txt
|
||||
|
|
|
@ -3,7 +3,6 @@ from django.core.cache import caches
|
|||
from django.utils import translation
|
||||
|
||||
import responses
|
||||
import caching
|
||||
import pytest
|
||||
|
||||
from multidb import pinning
|
||||
|
@ -111,9 +110,6 @@ def default_prefixer(settings):
|
|||
def test_pre_setup(request, tmpdir, settings):
|
||||
caches['default'].clear()
|
||||
caches['filesystem'].clear()
|
||||
# Override django-cache-machine caching.base.TIMEOUT because it's
|
||||
# computed too early, before settings_test.py is imported.
|
||||
caching.base.TIMEOUT = settings.CACHE_COUNT_TIMEOUT
|
||||
|
||||
translation.trans_real.deactivate()
|
||||
# Django fails to clear this cache.
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
## Forked.
|
||||
-e git+https://github.com/EnTeQuAk/django-cache-machine@1cac98a3e1dcc3cb654665cc67b6b15ab60d62c4#egg=django-cache-machine
|
|
@ -26,10 +26,6 @@ PAYPAL_PERMISSIONS_URL = ''
|
|||
|
||||
SITE_URL = 'http://testserver'
|
||||
|
||||
# COUNT() caching can't be invalidated, it just expires after x seconds. This
|
||||
# is just too annoying for tests, so disable it.
|
||||
CACHE_COUNT_TIMEOUT = -1
|
||||
|
||||
# We don't want to share cache state between processes. Always use the local
|
||||
# memcache backend for tests.
|
||||
#
|
||||
|
|
|
@ -44,8 +44,6 @@ class GroupUser(models.Model):
|
|||
del self.user.groups_list
|
||||
except AttributeError:
|
||||
pass
|
||||
# Help cache-machine invalidate the group-related queries...
|
||||
Group.objects.invalidate(self.group, *self.user.groups.all())
|
||||
|
||||
|
||||
@dispatch.receiver(signals.post_save, sender=GroupUser,
|
||||
|
|
|
@ -162,7 +162,6 @@ class PermissionsTestMixin(object):
|
|||
# Add a second group membership to test duplicates
|
||||
group2 = Group.objects.create(name='b', rules='Foo:Bar,Addons:Edit')
|
||||
GroupUser.objects.create(group=group2, user=self.user)
|
||||
Group.objects.invalidate(*Group.objects.all())
|
||||
assert self.serializer(self.user).data['permissions'] == [
|
||||
'Addons:Edit', 'Addons:Review', 'Foo:Bar', 'Personas:Review']
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ def _change_last_updated(next):
|
|||
|
||||
log.debug('Updating %s add-ons' % len(changes))
|
||||
# Update + invalidate.
|
||||
qs = Addon.objects.no_cache().filter(id__in=changes).no_transforms()
|
||||
qs = Addon.objects.filter(id__in=changes).no_transforms()
|
||||
for addon in qs:
|
||||
addon.update(last_updated=changes[addon.id])
|
||||
|
||||
|
@ -143,7 +143,7 @@ def addon_last_updated():
|
|||
_change_last_updated(next)
|
||||
|
||||
# Get anything that didn't match above.
|
||||
other = (Addon.objects.no_cache().filter(last_updated__isnull=True)
|
||||
other = (Addon.objects.filter(last_updated__isnull=True)
|
||||
.values_list('id', 'created'))
|
||||
_change_last_updated(dict(other))
|
||||
|
||||
|
@ -191,7 +191,7 @@ def hide_disabled_files():
|
|||
ids = (File.objects.filter(q | Q(status=amo.STATUS_DISABLED))
|
||||
.values_list('id', flat=True))
|
||||
for chunk in chunked(ids, 300):
|
||||
qs = File.objects.no_cache().filter(id__in=chunk)
|
||||
qs = File.objects.filter(id__in=chunk)
|
||||
qs = qs.select_related('version')
|
||||
for f in qs:
|
||||
f.hide_disabled_file()
|
||||
|
@ -237,7 +237,7 @@ def deliver_hotness():
|
|||
one_week = now - timedelta(days=7)
|
||||
four_weeks = now - timedelta(days=28)
|
||||
for ids in chunked(all_ids, 300):
|
||||
addons = Addon.objects.no_cache().filter(id__in=ids).no_transforms()
|
||||
addons = Addon.objects.filter(id__in=ids).no_transforms()
|
||||
ids = [a.id for a in addons if a.id not in frozen]
|
||||
qs = (UpdateCount.objects.filter(addon__in=ids)
|
||||
.values_list('addon').annotate(Avg('count')))
|
||||
|
|
|
@ -556,7 +556,7 @@ class EditThemeForm(AddonFormBase):
|
|||
|
||||
super(AddonFormBase, self).__init__(*args, **kw)
|
||||
|
||||
addon = Addon.objects.no_cache().get(id=self.instance.id)
|
||||
addon = Addon.objects.get(id=self.instance.id)
|
||||
persona = addon.persona
|
||||
|
||||
# Allow theme artists to localize Name and Description.
|
||||
|
|
|
@ -21,8 +21,6 @@ from django.utils.functional import cached_property
|
|||
from django.utils import translation
|
||||
from django.utils.translation import trans_real, ugettext_lazy as _
|
||||
|
||||
import caching.base as caching
|
||||
|
||||
from django_extensions.db.fields.json import JSONField
|
||||
from django_statsd.clients import statsd
|
||||
from jinja2.filters import do_dictsort
|
||||
|
@ -36,7 +34,7 @@ from olympia.addons.utils import (
|
|||
from olympia.amo.decorators import use_master, write
|
||||
from olympia.amo.models import (
|
||||
BasePreview, ManagerBase, manual_order, ModelBase, OnChangeMixin,
|
||||
SaveUpdateMixin, SlugField)
|
||||
SaveUpdateMixin, SlugField, BaseQuerySet)
|
||||
from olympia.amo.templatetags import jinja_helpers
|
||||
from olympia.amo.urlresolvers import reverse
|
||||
from olympia.amo.utils import (
|
||||
|
@ -150,7 +148,7 @@ def clean_slug(instance, slug_field='slug'):
|
|||
return instance
|
||||
|
||||
|
||||
class AddonQuerySet(caching.CachingQuerySet):
|
||||
class AddonQuerySet(BaseQuerySet):
|
||||
def id_or_slug(self, val):
|
||||
"""Get add-ons by id or slug."""
|
||||
if isinstance(val, basestring) and not val.isdigit():
|
||||
|
@ -364,7 +362,7 @@ class Addon(OnChangeMixin, ModelBase):
|
|||
|
||||
# The order of those managers is very important:
|
||||
# The first one discovered, if it has "use_for_related_fields = True"
|
||||
# (which it has if it's inheriting from caching.base.CachingManager), will
|
||||
# (which it has if it's inheriting `ManagerBase`), will
|
||||
# be used for relations like `version.addon`. We thus want one that is NOT
|
||||
# filtered in any case, we don't want a 500 if the addon is not found
|
||||
# (because it has the status amo.STATUS_DELETED for example).
|
||||
|
@ -723,7 +721,7 @@ class Addon(OnChangeMixin, ModelBase):
|
|||
'channel': amo.RELEASE_CHANNEL_LISTED,
|
||||
'files__status__in': statuses
|
||||
}
|
||||
return self.versions.no_cache().filter(**fltr).extra(
|
||||
return self.versions.filter(**fltr).extra(
|
||||
where=["""
|
||||
NOT EXISTS (
|
||||
SELECT 1 FROM files AS f2
|
||||
|
@ -1012,7 +1010,7 @@ class Addon(OnChangeMixin, ModelBase):
|
|||
if addon_dict is None:
|
||||
addon_dict = dict((a.id, a) for a in addons)
|
||||
|
||||
qs = (UserProfile.objects.no_cache()
|
||||
qs = (UserProfile.objects
|
||||
.filter(addons__in=addons, addonuser__listed=True)
|
||||
.extra(select={'addon_id': 'addons_users.addon_id',
|
||||
'position': 'addons_users.position'}))
|
||||
|
@ -1080,7 +1078,7 @@ class Addon(OnChangeMixin, ModelBase):
|
|||
addons = [a for a in addons if a.type != amo.ADDON_PERSONA]
|
||||
|
||||
# Persona-specific stuff
|
||||
for persona in Persona.objects.no_cache().filter(addon__in=personas):
|
||||
for persona in Persona.objects.filter(addon__in=personas):
|
||||
addon = addon_dict[persona.addon_id]
|
||||
addon.persona = persona
|
||||
|
||||
|
@ -1290,19 +1288,19 @@ class Addon(OnChangeMixin, ModelBase):
|
|||
"""
|
||||
status_change = Max('versions__files__datestatuschanged')
|
||||
public = (
|
||||
Addon.objects.no_cache().filter(
|
||||
Addon.objects.filter(
|
||||
status=amo.STATUS_PUBLIC,
|
||||
versions__files__status=amo.STATUS_PUBLIC)
|
||||
.exclude(type=amo.ADDON_PERSONA)
|
||||
.values('id').annotate(last_updated=status_change))
|
||||
|
||||
stati = amo.VALID_ADDON_STATUSES
|
||||
exp = (Addon.objects.no_cache().exclude(status__in=stati)
|
||||
exp = (Addon.objects.exclude(status__in=stati)
|
||||
.filter(versions__files__status__in=amo.VALID_FILE_STATUSES)
|
||||
.values('id')
|
||||
.annotate(last_updated=Max('versions__files__created')))
|
||||
|
||||
personas = (Addon.objects.no_cache().filter(type=amo.ADDON_PERSONA)
|
||||
personas = (Addon.objects.filter(type=amo.ADDON_PERSONA)
|
||||
.extra(select={'last_updated': 'created'}))
|
||||
return dict(public=public, exp=exp, personas=personas)
|
||||
|
||||
|
@ -1540,7 +1538,7 @@ class AddonReviewerFlags(ModelBase):
|
|||
notified_about_expiring_info_request = models.BooleanField(default=False)
|
||||
|
||||
|
||||
class Persona(caching.CachingMixin, models.Model):
|
||||
class Persona(models.Model):
|
||||
"""Personas-specific additions to the add-on model."""
|
||||
STATUS_CHOICES = amo.STATUS_CHOICES_PERSONA
|
||||
|
||||
|
@ -1565,8 +1563,6 @@ class Persona(caching.CachingMixin, models.Model):
|
|||
checksum = models.CharField(max_length=64, blank=True, default='')
|
||||
dupe_persona = models.ForeignKey('self', null=True)
|
||||
|
||||
objects = caching.CachingManager()
|
||||
|
||||
class Meta:
|
||||
db_table = 'personas'
|
||||
|
||||
|
@ -1739,14 +1735,12 @@ class MigratedLWT(OnChangeMixin, ModelBase):
|
|||
self.getpersonas_id = self.lightweight_theme.persona.persona_id
|
||||
|
||||
|
||||
class AddonCategory(caching.CachingMixin, models.Model):
|
||||
class AddonCategory(models.Model):
|
||||
addon = models.ForeignKey(Addon, on_delete=models.CASCADE)
|
||||
category = models.ForeignKey('Category')
|
||||
feature = models.BooleanField(default=False)
|
||||
feature_locales = models.CharField(max_length=255, default='', null=True)
|
||||
|
||||
objects = caching.CachingManager()
|
||||
|
||||
class Meta:
|
||||
db_table = 'addons_categories'
|
||||
unique_together = ('addon', 'category')
|
||||
|
@ -1756,8 +1750,7 @@ class AddonCategory(caching.CachingMixin, models.Model):
|
|||
return get_creatured_ids(category, lang)
|
||||
|
||||
|
||||
class AddonUser(caching.CachingMixin, OnChangeMixin, SaveUpdateMixin,
|
||||
models.Model):
|
||||
class AddonUser(OnChangeMixin, SaveUpdateMixin, models.Model):
|
||||
addon = models.ForeignKey(Addon, on_delete=models.CASCADE)
|
||||
user = UserForeignKey()
|
||||
role = models.SmallIntegerField(default=amo.AUTHOR_ROLE_OWNER,
|
||||
|
@ -1765,8 +1758,6 @@ class AddonUser(caching.CachingMixin, OnChangeMixin, SaveUpdateMixin,
|
|||
listed = models.BooleanField(_(u'Listed'), default=True)
|
||||
position = models.IntegerField(default=0)
|
||||
|
||||
objects = caching.CachingManager()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(AddonUser, self).__init__(*args, **kwargs)
|
||||
self._original_role = self.role
|
||||
|
|
|
@ -79,7 +79,7 @@ def update_last_updated(addon_id):
|
|||
def update_appsupport(ids):
|
||||
log.info("[%s@None] Updating appsupport for %s." % (len(ids), ids))
|
||||
|
||||
addons = Addon.objects.no_cache().filter(id__in=ids).no_transforms()
|
||||
addons = Addon.objects.filter(id__in=ids).no_transforms()
|
||||
support = []
|
||||
for addon in addons:
|
||||
for app, appver in addon.compatible_apps.items():
|
||||
|
@ -99,9 +99,6 @@ def update_appsupport(ids):
|
|||
AppSupport.objects.filter(addon__id__in=ids).delete()
|
||||
AppSupport.objects.bulk_create(support)
|
||||
|
||||
# All our updates were sql, so invalidate manually.
|
||||
Addon.objects.invalidate(*addons)
|
||||
|
||||
|
||||
@task
|
||||
def delete_preview_files(id, **kw):
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
{% from "addons/listing/macros.html" import heading, item_info %}
|
||||
{% set collection = collection or None %}
|
||||
{% set collection_cache_key = collection.cache_key if collection else 'collection-none' %}
|
||||
{% set userpk = request.user.pk if request.user.is_authenticated() else '' %}
|
||||
{% for addon in addons %}
|
||||
<div class="item">
|
||||
|
|
|
@ -159,7 +159,7 @@ class TestTagsForm(TestCase):
|
|||
return form
|
||||
|
||||
def get_tag_text(self):
|
||||
return [t.tag_text for t in self.addon.tags.no_cache().all()]
|
||||
return [t.tag_text for t in self.addon.tags.all()]
|
||||
|
||||
def test_tags(self):
|
||||
self.add_tags('foo, bar')
|
||||
|
|
|
@ -155,7 +155,7 @@ class TestAddonIndexer(TestCase):
|
|||
if 'index' in prop)
|
||||
|
||||
def _extract(self):
|
||||
qs = Addon.unfiltered.filter(id__in=[self.addon.pk]).no_cache()
|
||||
qs = Addon.unfiltered.filter(id__in=[self.addon.pk])
|
||||
for t in self.transforms:
|
||||
qs = qs.transform(t)
|
||||
self.addon = list(qs)[0]
|
||||
|
|
|
@ -1768,10 +1768,10 @@ class TestUpdateStatus(TestCase):
|
|||
addon = Addon.objects.create(type=amo.ADDON_EXTENSION)
|
||||
addon.status = amo.STATUS_NOMINATED
|
||||
addon.save()
|
||||
assert Addon.objects.no_cache().get(pk=addon.pk).status == (
|
||||
assert Addon.objects.get(pk=addon.pk).status == (
|
||||
amo.STATUS_NOMINATED)
|
||||
Version.objects.create(addon=addon)
|
||||
assert Addon.objects.no_cache().get(pk=addon.pk).status == (
|
||||
assert Addon.objects.get(pk=addon.pk).status == (
|
||||
amo.STATUS_NULL)
|
||||
|
||||
def test_no_valid_file_ends_with_NULL(self):
|
||||
|
@ -1781,22 +1781,22 @@ class TestUpdateStatus(TestCase):
|
|||
version=version)
|
||||
addon.status = amo.STATUS_NOMINATED
|
||||
addon.save()
|
||||
assert Addon.objects.no_cache().get(pk=addon.pk).status == (
|
||||
assert Addon.objects.get(pk=addon.pk).status == (
|
||||
amo.STATUS_NOMINATED)
|
||||
f.status = amo.STATUS_DISABLED
|
||||
f.save()
|
||||
assert Addon.objects.no_cache().get(pk=addon.pk).status == (
|
||||
assert Addon.objects.get(pk=addon.pk).status == (
|
||||
amo.STATUS_NULL)
|
||||
|
||||
def test_unlisted_versions_ignored(self):
|
||||
addon = addon_factory(status=amo.STATUS_PUBLIC)
|
||||
addon.update_status()
|
||||
assert Addon.objects.no_cache().get(pk=addon.pk).status == (
|
||||
assert Addon.objects.get(pk=addon.pk).status == (
|
||||
amo.STATUS_PUBLIC)
|
||||
|
||||
addon.current_version.update(channel=amo.RELEASE_CHANNEL_UNLISTED)
|
||||
# update_status will have been called via versions.models.update_status
|
||||
assert Addon.objects.no_cache().get(pk=addon.pk).status == (
|
||||
assert Addon.objects.get(pk=addon.pk).status == (
|
||||
amo.STATUS_NULL) # No listed versions so now NULL
|
||||
|
||||
|
||||
|
|
|
@ -12,11 +12,11 @@ from django.utils.translation import ugettext
|
|||
import olympia.core.logger
|
||||
|
||||
from olympia import amo
|
||||
from olympia.lib.cache import memoize, memoize_key
|
||||
from olympia.amo.utils import normalize_string
|
||||
from olympia.constants.categories import CATEGORIES_BY_ID
|
||||
from olympia.discovery.utils import call_recommendation_server
|
||||
from olympia.translations.fields import LocaleList, LocaleValidationError
|
||||
from olympia.lib.cache import memoize, memoize_key
|
||||
|
||||
|
||||
log = olympia.core.logger.getLogger('z.redis')
|
||||
|
@ -31,7 +31,7 @@ def clear_get_featured_ids_cache(*args, **kwargs):
|
|||
cache.delete(cache_key)
|
||||
|
||||
|
||||
@memoize('addons:featured', time=60 * 10)
|
||||
@memoize('addons:featured', timeout=60 * 10)
|
||||
def get_featured_ids(app=None, lang=None, type=None, types=None):
|
||||
from olympia.addons.models import Addon
|
||||
ids = []
|
||||
|
@ -65,7 +65,7 @@ def get_featured_ids(app=None, lang=None, type=None, types=None):
|
|||
return map(int, ids)
|
||||
|
||||
|
||||
@memoize('addons:creatured', time=60 * 10)
|
||||
@memoize('addons:creatured', timeout=60 * 10)
|
||||
def get_creatured_ids(category, lang=None):
|
||||
from olympia.addons.models import Addon
|
||||
from olympia.bandwagon.models import FeaturedCollection
|
||||
|
|
|
@ -47,7 +47,7 @@ from olympia.search.filters import (
|
|||
SortingFilter)
|
||||
from olympia.translations.query import order_by_translation
|
||||
from olympia.versions.models import Version
|
||||
from olympia.lib.cache import cache_get_or_set, make_key
|
||||
from olympia.lib.cache import make_key, cache_get_or_set
|
||||
|
||||
from .decorators import addon_view_factory
|
||||
from .indexers import AddonIndexer
|
||||
|
@ -144,8 +144,7 @@ def extension_detail(request, addon):
|
|||
def _category_personas(qs, limit):
|
||||
def fetch_personas():
|
||||
return randslice(qs, limit=limit)
|
||||
# TODO: .query_key comes from cache-machine, find replacement
|
||||
key = make_key('cat-personas:' + qs.query_key(), normalize=True)
|
||||
key = make_key('cat-personas:' + str(qs.query), normalize=True)
|
||||
return cache_get_or_set(key, fetch_personas)
|
||||
|
||||
|
||||
|
@ -453,9 +452,7 @@ class AddonViewSet(RetrieveModelMixin, GenericViewSet):
|
|||
lookup_value_regex = '[^/]+' # Allow '.' for email-like guids.
|
||||
|
||||
def get_queryset(self):
|
||||
"""Return queryset to be used for the view. We implement our own that
|
||||
does not depend on self.queryset to avoid cache-machine caching the
|
||||
queryset too agressively (mozilla/addons-frontend#2497)."""
|
||||
"""Return queryset to be used for the view."""
|
||||
# Special case: admins - and only admins - can see deleted add-ons.
|
||||
# This is handled outside a permission class because that condition
|
||||
# would pollute all other classes otherwise.
|
||||
|
@ -907,7 +904,6 @@ class LanguageToolsView(ListAPIView):
|
|||
"""
|
||||
return (
|
||||
Addon.objects.public()
|
||||
.no_cache()
|
||||
.filter(appsupport__app=application, type__in=addon_types,
|
||||
target_locale__isnull=False)
|
||||
.exclude(target_locale='')
|
||||
|
@ -939,7 +935,7 @@ class LanguageToolsView(ListAPIView):
|
|||
# can avoid loading translations by removing transforms and then
|
||||
# re-applying the default one that takes care of the files and compat
|
||||
# info.
|
||||
versions_qs = Version.objects.no_cache().filter(
|
||||
versions_qs = Version.objects.filter(
|
||||
apps__application=application,
|
||||
apps__min__version_int__lte=appversions['min'],
|
||||
apps__max__version_int__gte=appversions['max'],
|
||||
|
|
|
@ -102,24 +102,6 @@ json_view.error = lambda s: http.HttpResponseBadRequest(
|
|||
json.dumps(s), content_type='application/json')
|
||||
|
||||
|
||||
class skip_cache(object):
|
||||
def __init__(self, f):
|
||||
functools.update_wrapper(self, f)
|
||||
# Do this after `update_wrapper`, or it may be overwritten
|
||||
# by a value from `f.__dict__`.
|
||||
self.f = f
|
||||
|
||||
def __call__(self, *args, **kw):
|
||||
with context.skip_cache():
|
||||
return self.f(*args, **kw)
|
||||
|
||||
def __repr__(self):
|
||||
return '<SkipCache %r>' % self.f
|
||||
|
||||
def __get__(self, obj, typ=None):
|
||||
return skip_cache(self.f.__get__(obj, typ))
|
||||
|
||||
|
||||
def use_master(f):
|
||||
@functools.wraps(f)
|
||||
def wrapper(*args, **kw):
|
||||
|
@ -129,7 +111,7 @@ def use_master(f):
|
|||
|
||||
|
||||
def write(f):
|
||||
return use_master(skip_cache(f))
|
||||
return use_master(f)
|
||||
|
||||
|
||||
def set_modified_on(f):
|
||||
|
|
|
@ -225,6 +225,7 @@ class SetRemoteAddrFromForwardedFor(object):
|
|||
|
||||
known = getattr(settings, 'KNOWN_PROXIES', [])
|
||||
ips.reverse()
|
||||
|
||||
for ip in ips:
|
||||
request.META['REMOTE_ADDR'] = ip
|
||||
if ip not in known:
|
||||
|
|
|
@ -1,20 +1,15 @@
|
|||
import contextlib
|
||||
import os
|
||||
import threading
|
||||
import time
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.files.storage import default_storage as storage
|
||||
from django.db import models, transaction
|
||||
from django.utils import translation
|
||||
from django.utils.encoding import force_text
|
||||
|
||||
import caching.base
|
||||
import elasticsearch
|
||||
import multidb.pinning
|
||||
|
||||
from django_statsd.clients import statsd
|
||||
|
||||
import olympia.core.logger
|
||||
import olympia.lib.queryset_transform as queryset_transform
|
||||
|
||||
|
@ -23,12 +18,6 @@ from olympia.translations.hold import save_translations
|
|||
from . import search
|
||||
|
||||
|
||||
# Store whether we should be skipping cache-machine for this thread or not.
|
||||
# Note that because the value is initialized at import time, we can't use
|
||||
# override_settings() on CACHE_MACHINE_ENABLED.
|
||||
_locals = threading.local()
|
||||
_locals.skip_cache = not settings.CACHE_MACHINE_ENABLED
|
||||
|
||||
log = olympia.core.logger.getLogger('z.addons')
|
||||
|
||||
|
||||
|
@ -43,18 +32,7 @@ def use_master():
|
|||
multidb.pinning._locals.pinned = old
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def skip_cache():
|
||||
"""Within this context, no queries come from cache."""
|
||||
old = getattr(_locals, 'skip_cache', not settings.CACHE_MACHINE_ENABLED)
|
||||
_locals.skip_cache = True
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
_locals.skip_cache = old
|
||||
|
||||
|
||||
class TransformQuerySet(queryset_transform.TransformQuerySet):
|
||||
class BaseQuerySet(queryset_transform.TransformQuerySet):
|
||||
|
||||
def pop_transforms(self):
|
||||
qs = self._clone()
|
||||
|
@ -72,11 +50,6 @@ class TransformQuerySet(queryset_transform.TransformQuerySet):
|
|||
return (self.no_transforms().extra(select={'_only_trans': 1})
|
||||
.transform(transformer.get_trans))
|
||||
|
||||
def transform(self, fn):
|
||||
from . import decorators
|
||||
f = decorators.skip_cache(fn)
|
||||
return super(TransformQuerySet, self).transform(f)
|
||||
|
||||
|
||||
class RawQuerySet(models.query.RawQuerySet):
|
||||
"""A RawQuerySet with __len__."""
|
||||
|
@ -94,20 +67,17 @@ class RawQuerySet(models.query.RawQuerySet):
|
|||
return len(list(self.__iter__()))
|
||||
|
||||
|
||||
class CachingRawQuerySet(RawQuerySet, caching.base.CachingRawQuerySet):
|
||||
"""A RawQuerySet with __len__ and caching."""
|
||||
|
||||
|
||||
# Make TransformQuerySet one of CachingQuerySet's parents so that we can do
|
||||
# transforms on objects and then get them cached.
|
||||
CachingQuerySet = caching.base.CachingQuerySet
|
||||
CachingQuerySet.__bases__ = (TransformQuerySet,) + CachingQuerySet.__bases__
|
||||
|
||||
|
||||
class UncachedManagerBase(models.Manager):
|
||||
class ManagerBase(models.Manager):
|
||||
# This needs to be set so that this manager class is being used
|
||||
# for related objects too. This helps resolving translation fields
|
||||
# on related fields.
|
||||
# This also ensures we don't ignore soft-deleted items when traversing
|
||||
# relations, if they are hidden by the objects manager, like we
|
||||
# do with `addons.models:Addon`.
|
||||
use_for_related_fields = True
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self._with_translations(TransformQuerySet(self.model))
|
||||
qs = self._with_translations(BaseQuerySet(self.model))
|
||||
return qs
|
||||
|
||||
def _with_translations(self, qs):
|
||||
|
@ -144,37 +114,6 @@ class UncachedManagerBase(models.Manager):
|
|||
return self.create(**kw), True
|
||||
|
||||
|
||||
class ManagerBase(caching.base.CachingManager, UncachedManagerBase):
|
||||
"""
|
||||
Base for all managers in AMO.
|
||||
|
||||
Returns TransformQuerySets from the queryset_transform project.
|
||||
|
||||
If a model has translated fields, they'll be attached through a transform
|
||||
function.
|
||||
"""
|
||||
|
||||
def get_queryset(self):
|
||||
qs = super(ManagerBase, self).get_queryset()
|
||||
if getattr(_locals, 'skip_cache', False):
|
||||
qs = qs.no_cache()
|
||||
return self._with_translations(qs)
|
||||
|
||||
def raw(self, raw_query, params=None, *args, **kwargs):
|
||||
return CachingRawQuerySet(raw_query, self.model, params=params,
|
||||
using=self._db, *args, **kwargs)
|
||||
|
||||
def post_save(self, *args, **kwargs):
|
||||
# Measure cache invalidation after saving an object.
|
||||
with statsd.timer('cache_machine.manager.post_save'):
|
||||
return super(ManagerBase, self).post_save(*args, **kwargs)
|
||||
|
||||
def post_delete(self, *args, **kwargs):
|
||||
# Measure cache invalidation after deleting an object.
|
||||
with statsd.timer('cache_machine.manager.post_delete'):
|
||||
return super(ManagerBase, self).post_delete(*args, **kwargs)
|
||||
|
||||
|
||||
class _NoChangeInstance(object):
|
||||
"""A proxy for object instances to make safe operations within an
|
||||
OnChangeMixin.on_change() callback.
|
||||
|
@ -389,10 +328,9 @@ class SaveUpdateMixin(object):
|
|||
return super(SaveUpdateMixin, self).save(**kwargs)
|
||||
|
||||
|
||||
class UncachedModelBase(SearchMixin, SaveUpdateMixin, models.Model):
|
||||
class ModelBase(SearchMixin, SaveUpdateMixin, models.Model):
|
||||
"""
|
||||
Base class for AMO models to abstract some common features
|
||||
(without cache-machine).
|
||||
Base class for AMO models to abstract some common features.
|
||||
|
||||
* Adds automatic created and modified fields to the model.
|
||||
* Fetches all translations in one subsequent query during initialization.
|
||||
|
@ -401,7 +339,7 @@ class UncachedModelBase(SearchMixin, SaveUpdateMixin, models.Model):
|
|||
created = models.DateTimeField(auto_now_add=True)
|
||||
modified = models.DateTimeField(auto_now=True)
|
||||
|
||||
objects = UncachedManagerBase()
|
||||
objects = ManagerBase()
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
@ -417,29 +355,6 @@ class UncachedModelBase(SearchMixin, SaveUpdateMixin, models.Model):
|
|||
return self._meta.app_label, self._meta.model_name, self.pk
|
||||
|
||||
|
||||
class ModelBase(caching.base.CachingMixin, UncachedModelBase, models.Model):
|
||||
"""
|
||||
Base class for AMO models to abstract some common features.
|
||||
|
||||
* Adds automatic created and modified fields to the model.
|
||||
* Fetches all translations in one subsequent query during initialization.
|
||||
"""
|
||||
objects = ManagerBase()
|
||||
|
||||
class Meta(UncachedModelBase.Meta):
|
||||
abstract = True
|
||||
|
||||
@classmethod
|
||||
def _cache_key(cls, pk, db):
|
||||
"""
|
||||
Custom django-cache-machine cache key implementation that avoids having
|
||||
the real db in the key, since we are only using master-slaves we don't
|
||||
need it and it avoids invalidation bugs with FETCH_BY_ID.
|
||||
"""
|
||||
key_parts = ('o', cls._meta, pk, 'default')
|
||||
return ':'.join(map(force_text, key_parts))
|
||||
|
||||
|
||||
def manual_order(qs, pks, pk_name='id'):
|
||||
"""
|
||||
Given a query set and a list of primary keys, return a set of objects from
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import mock
|
||||
import pytest
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.files.storage import default_storage as storage
|
||||
|
||||
from mock import Mock
|
||||
|
@ -29,24 +27,6 @@ class ManualOrderTest(TestCase):
|
|||
assert semi_arbitrary_order == [addon.id for addon in addons]
|
||||
|
||||
|
||||
def test_skip_cache():
|
||||
assert (
|
||||
getattr(amo_models._locals, 'skip_cache') is
|
||||
not settings.CACHE_MACHINE_ENABLED)
|
||||
|
||||
setattr(amo_models._locals, 'skip_cache', False)
|
||||
|
||||
with amo_models.skip_cache():
|
||||
assert amo_models._locals.skip_cache
|
||||
with amo_models.skip_cache():
|
||||
assert amo_models._locals.skip_cache
|
||||
assert amo_models._locals.skip_cache
|
||||
|
||||
assert not amo_models._locals.skip_cache
|
||||
|
||||
setattr(amo_models._locals, 'skip_cache', settings.CACHE_MACHINE_ENABLED)
|
||||
|
||||
|
||||
def test_use_master():
|
||||
local = amo_models.multidb.pinning._locals
|
||||
assert not getattr(local, 'pinned', False)
|
||||
|
@ -162,24 +142,6 @@ class TestModelBase(TestCase):
|
|||
Addon.get_unfiltered_manager() == Addon.unfiltered
|
||||
UserProfile.get_unfiltered_manager() == UserProfile.objects
|
||||
|
||||
def test_measure_save_time(self):
|
||||
addon = Addon.objects.create(type=amo.ADDON_EXTENSION)
|
||||
with mock.patch('olympia.amo.models.statsd.timer') as timer:
|
||||
addon.save()
|
||||
timer.assert_any_call('cache_machine.manager.post_save')
|
||||
|
||||
def test_measure_delete_time(self):
|
||||
addon = Addon.objects.create(type=amo.ADDON_EXTENSION)
|
||||
with mock.patch('olympia.amo.models.statsd.timer') as timer:
|
||||
addon.delete()
|
||||
timer.assert_any_call('cache_machine.manager.post_delete')
|
||||
|
||||
|
||||
def test_cache_key():
|
||||
# Test that we are not taking the db into account when building our
|
||||
# cache keys for django-cache-machine. See bug 928881.
|
||||
assert Addon._cache_key(1, 'default') == Addon._cache_key(1, 'slave')
|
||||
|
||||
|
||||
class BasePreviewMixin(object):
|
||||
|
||||
|
|
|
@ -87,9 +87,9 @@ class TestCommands(TestCase):
|
|||
'.PyQuery', spec=True)
|
||||
def test_import_prod_versions(self, pyquery_mock):
|
||||
assert not AppVersion.objects.filter(
|
||||
application=amo.FIREFOX.id, version='53.0').no_cache().exists()
|
||||
application=amo.FIREFOX.id, version='53.0').exists()
|
||||
assert not AppVersion.objects.filter(
|
||||
application=amo.FIREFOX.id, version='53.*').no_cache().exists()
|
||||
application=amo.FIREFOX.id, version='53.*').exists()
|
||||
|
||||
# Result of PyQuery()
|
||||
MockedDoc = mock.Mock()
|
||||
|
@ -108,6 +108,6 @@ class TestCommands(TestCase):
|
|||
call_command('import_prod_versions')
|
||||
|
||||
assert AppVersion.objects.filter(
|
||||
application=amo.FIREFOX.id, version='53.0').no_cache().exists()
|
||||
application=amo.FIREFOX.id, version='53.0').exists()
|
||||
assert AppVersion.objects.filter(
|
||||
application=amo.FIREFOX.id, version='53.*').no_cache().exists()
|
||||
application=amo.FIREFOX.id, version='53.*').exists()
|
||||
|
|
|
@ -13,7 +13,7 @@ from olympia import activity, amo
|
|||
from olympia.access import acl
|
||||
from olympia.addons.models import Addon
|
||||
from olympia.addons.utils import clear_get_featured_ids_cache
|
||||
from olympia.amo.models import UncachedManagerBase, UncachedModelBase
|
||||
from olympia.amo.models import ManagerBase, ModelBase
|
||||
from olympia.amo.templatetags.jinja_helpers import (
|
||||
absolutify, user_media_path, user_media_url)
|
||||
from olympia.amo.urlresolvers import reverse
|
||||
|
@ -60,7 +60,7 @@ class CollectionQuerySet(queryset_transform.TransformQuerySet):
|
|||
select_params=(addon_id,))
|
||||
|
||||
|
||||
class CollectionManager(UncachedManagerBase):
|
||||
class CollectionManager(ManagerBase):
|
||||
|
||||
def get_queryset(self):
|
||||
qs = super(CollectionManager, self).get_queryset()
|
||||
|
@ -84,7 +84,7 @@ class CollectionManager(UncachedManagerBase):
|
|||
return self.filter(author=user.pk)
|
||||
|
||||
|
||||
class Collection(UncachedModelBase):
|
||||
class Collection(ModelBase):
|
||||
TYPE_CHOICES = amo.COLLECTION_CHOICES.items()
|
||||
|
||||
# TODO: Use models.UUIDField but it uses max_length=32 hex (no hyphen)
|
||||
|
@ -132,7 +132,7 @@ class Collection(UncachedModelBase):
|
|||
|
||||
top_tags = TopTags()
|
||||
|
||||
class Meta(UncachedModelBase.Meta):
|
||||
class Meta(ModelBase.Meta):
|
||||
db_table = 'collections'
|
||||
unique_together = (('author', 'slug'),)
|
||||
|
||||
|
@ -379,7 +379,7 @@ models.signals.post_delete.connect(Collection.post_delete, sender=Collection,
|
|||
dispatch_uid='coll.post_delete')
|
||||
|
||||
|
||||
class CollectionAddon(UncachedModelBase):
|
||||
class CollectionAddon(ModelBase):
|
||||
addon = models.ForeignKey(Addon)
|
||||
collection = models.ForeignKey(Collection)
|
||||
# category (deprecated: for "Fashion Your Firefox")
|
||||
|
@ -392,7 +392,7 @@ class CollectionAddon(UncachedModelBase):
|
|||
help_text='Add-ons are displayed in ascending order '
|
||||
'based on this field.')
|
||||
|
||||
class Meta(UncachedModelBase.Meta):
|
||||
class Meta(ModelBase.Meta):
|
||||
db_table = 'addons_collections'
|
||||
unique_together = (('addon', 'collection'),)
|
||||
|
||||
|
@ -428,11 +428,11 @@ models.signals.post_delete.connect(CollectionAddon.post_delete,
|
|||
dispatch_uid='coll.post_delete')
|
||||
|
||||
|
||||
class CollectionWatcher(UncachedModelBase):
|
||||
class CollectionWatcher(ModelBase):
|
||||
collection = models.ForeignKey(Collection, related_name='following')
|
||||
user = models.ForeignKey(UserProfile)
|
||||
|
||||
class Meta(UncachedModelBase.Meta):
|
||||
class Meta(ModelBase.Meta):
|
||||
db_table = 'collection_subscriptions'
|
||||
|
||||
@staticmethod
|
||||
|
@ -472,7 +472,7 @@ models.signals.post_delete.connect(CollectionVote.post_save_or_delete,
|
|||
sender=CollectionVote)
|
||||
|
||||
|
||||
class FeaturedCollection(UncachedModelBase):
|
||||
class FeaturedCollection(ModelBase):
|
||||
application = models.PositiveIntegerField(choices=amo.APPS_CHOICES,
|
||||
db_column='application_id')
|
||||
collection = models.ForeignKey(Collection)
|
||||
|
@ -497,7 +497,7 @@ models.signals.post_delete.connect(FeaturedCollection.post_save_or_delete,
|
|||
sender=FeaturedCollection)
|
||||
|
||||
|
||||
class MonthlyPick(UncachedModelBase):
|
||||
class MonthlyPick(ModelBase):
|
||||
addon = models.ForeignKey(Addon)
|
||||
blurb = models.TextField()
|
||||
image = models.URLField()
|
||||
|
|
|
@ -83,10 +83,9 @@ class ThisCollectionDefault(object):
|
|||
|
||||
class CollectionAddonSerializer(serializers.ModelSerializer):
|
||||
addon = SplitField(
|
||||
SlugOrPrimaryKeyRelatedField(
|
||||
# .no_cache() because django-cache-machine blows up otherwise.
|
||||
# Only used for writes (this is input field) so no perf concerns.
|
||||
queryset=Addon.objects.public().no_cache()),
|
||||
# Only used for writes (this is input field), so there are no perf
|
||||
# concerns and we don't use any special caching.
|
||||
SlugOrPrimaryKeyRelatedField(queryset=Addon.objects.public()),
|
||||
AddonSerializer())
|
||||
notes = TranslationSerializerField(source='comments', required=False)
|
||||
collection = serializers.HiddenField(default=ThisCollectionDefault())
|
||||
|
|
|
@ -930,7 +930,7 @@ class TestWatching(TestCase):
|
|||
class TestCollectionForm(TestCase):
|
||||
fixtures = ['base/collection_57181', 'users/test_backends']
|
||||
|
||||
@patch('olympia.amo.models.UncachedModelBase.update')
|
||||
@patch('olympia.amo.models.ModelBase.update')
|
||||
def test_icon(self, update_mock):
|
||||
collection = Collection.objects.get(pk=57181)
|
||||
# TODO(andym): altering this form is too complicated, can we simplify?
|
||||
|
|
|
@ -79,9 +79,6 @@ SLAVE_DATABASES = ['slave']
|
|||
|
||||
CACHE_MIDDLEWARE_KEY_PREFIX = CACHE_PREFIX
|
||||
|
||||
# Disable cache-machine on dev to prepare for its removal.
|
||||
CACHE_MACHINE_ENABLED = False
|
||||
|
||||
CACHES = {
|
||||
'filesystem': {
|
||||
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
|
||||
|
@ -119,8 +116,6 @@ REDIS_BACKENDS = {
|
|||
'slave': get_redis_settings(env('REDIS_BACKENDS_SLAVE'))
|
||||
}
|
||||
|
||||
CACHE_MACHINE_USE_REDIS = True
|
||||
|
||||
csp = 'csp.middleware.CSPMiddleware'
|
||||
|
||||
ES_TIMEOUT = 60
|
||||
|
|
|
@ -104,8 +104,6 @@ REDIS_BACKENDS = {
|
|||
'slave': get_redis_settings(env('REDIS_BACKENDS_SLAVE'))
|
||||
}
|
||||
|
||||
CACHE_MACHINE_USE_REDIS = True
|
||||
|
||||
ES_TIMEOUT = 60
|
||||
ES_HOSTS = env('ES_HOSTS')
|
||||
ES_URLS = ['http://%s' % h for h in ES_HOSTS]
|
||||
|
|
|
@ -78,9 +78,6 @@ SLAVE_DATABASES = ['slave']
|
|||
|
||||
CACHE_MIDDLEWARE_KEY_PREFIX = CACHE_PREFIX
|
||||
|
||||
# Disable cache-machine on dev to prepare for its removal.
|
||||
CACHE_MACHINE_ENABLED = False
|
||||
|
||||
CACHES = {
|
||||
'filesystem': {
|
||||
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
|
||||
|
@ -115,8 +112,6 @@ REDIS_BACKENDS = {
|
|||
'slave': get_redis_settings(env('REDIS_BACKENDS_SLAVE'))
|
||||
}
|
||||
|
||||
CACHE_MACHINE_USE_REDIS = True
|
||||
|
||||
csp = 'csp.middleware.CSPMiddleware'
|
||||
|
||||
ES_TIMEOUT = 60
|
||||
|
|
|
@ -36,7 +36,7 @@ def change():
|
|||
k = 0
|
||||
print('Changing %s files' % len(files))
|
||||
for chunk in chunked(files, 100):
|
||||
for file in File.objects.no_cache().filter(pk__in=chunk):
|
||||
for file in File.objects.filter(pk__in=chunk):
|
||||
file.platform = amo.PLATFORM_ALL.id
|
||||
if not file.datestatuschanged:
|
||||
file.datestatuschanged = datetime.now()
|
||||
|
@ -52,7 +52,7 @@ def report():
|
|||
.filter(addon__type=amo.ADDON_SEARCH)
|
||||
.filter(files_count__gt=1))
|
||||
for chunk in chunked(versions, 100):
|
||||
for version in Version.objects.no_cache().filter(pk__in=chunk):
|
||||
for version in Version.objects.filter(pk__in=chunk):
|
||||
print('Addon: %s, %s' % (version.addon.pk,
|
||||
version.addon.name))
|
||||
print('Version: %s - %s files' % (version.pk,
|
||||
|
|
|
@ -61,7 +61,7 @@ class BaseTestEdit(TestCase):
|
|||
self.url = self.addon.get_dev_url()
|
||||
|
||||
def get_addon(self):
|
||||
return Addon.objects.no_cache().get(id=3615)
|
||||
return Addon.objects.get(id=3615)
|
||||
|
||||
def get_url(self, section, edit=False):
|
||||
args = [self.addon.slug, section]
|
||||
|
|
|
@ -27,10 +27,10 @@ class TestOwnership(TestCase):
|
|||
return formset(*args, **defaults)
|
||||
|
||||
def get_version(self):
|
||||
return Version.objects.no_cache().get(id=self.version.id)
|
||||
return Version.objects.get(id=self.version.id)
|
||||
|
||||
def get_addon(self):
|
||||
return Addon.objects.no_cache().get(id=self.addon.id)
|
||||
return Addon.objects.get(id=self.addon.id)
|
||||
|
||||
|
||||
class TestEditPolicy(TestOwnership):
|
||||
|
@ -246,7 +246,7 @@ class TestEditAuthor(TestOwnership):
|
|||
assert ActivityLog.objects.all().count() == orig
|
||||
|
||||
def test_success_add_user(self):
|
||||
qs = (AddonUser.objects.no_cache().filter(addon=3615)
|
||||
qs = (AddonUser.objects.filter(addon=3615)
|
||||
.values_list('user', flat=True))
|
||||
assert list(qs.all()) == [55021]
|
||||
|
||||
|
@ -296,8 +296,7 @@ class TestEditAuthor(TestOwnership):
|
|||
data = self.formset(one.initial, two.initial, empty, initial_count=2)
|
||||
response = self.client.post(self.url, data)
|
||||
self.assert3xx(response, self.url, 302)
|
||||
assert not AddonUser.objects.no_cache().get(
|
||||
addon=3615, user=999).listed
|
||||
assert not AddonUser.objects.get(addon=3615, user=999).listed
|
||||
|
||||
def test_change_user_role(self):
|
||||
# Add an author b/c we can't edit anything about the current one.
|
||||
|
|
|
@ -83,7 +83,7 @@ class TestSubmitBase(TestCase):
|
|||
self.addon = self.get_addon()
|
||||
|
||||
def get_addon(self):
|
||||
return Addon.objects.no_cache().get(pk=3615)
|
||||
return Addon.objects.get(pk=3615)
|
||||
|
||||
def get_version(self):
|
||||
return self.get_addon().versions.latest()
|
||||
|
|
|
@ -571,7 +571,7 @@ class TestVersion(TestCase):
|
|||
class TestVersionEditMixin(object):
|
||||
|
||||
def get_addon(self):
|
||||
return Addon.objects.no_cache().get(id=3615)
|
||||
return Addon.objects.get(id=3615)
|
||||
|
||||
def get_version(self):
|
||||
return self.get_addon().current_version
|
||||
|
@ -798,7 +798,7 @@ class TestVersionEditSearchEngine(TestVersionEditMixin, TestCase):
|
|||
|
||||
response = self.client.post(self.url, dd)
|
||||
assert response.status_code == 302
|
||||
version = Addon.objects.no_cache().get(id=4594).current_version
|
||||
version = Addon.objects.get(id=4594).current_version
|
||||
assert unicode(version.releasenotes) == 'xx'
|
||||
assert unicode(version.approvalnotes) == 'yy'
|
||||
|
||||
|
@ -893,7 +893,7 @@ class TestVersionEditFiles(TestVersionEditBase):
|
|||
forms = self.client.get(self.url).context['file_form'].forms
|
||||
forms = map(initial, forms)
|
||||
self.client.post(self.url, self.formset(*forms, prefix='files'))
|
||||
assert File.objects.no_cache().get(pk=bsd.pk).platform == (
|
||||
assert File.objects.get(pk=bsd.pk).platform == (
|
||||
amo.PLATFORM_BSD.id)
|
||||
|
||||
def test_all_unsupported_platforms_change(self):
|
||||
|
@ -903,7 +903,7 @@ class TestVersionEditFiles(TestVersionEditBase):
|
|||
# Update the file platform to Linux:
|
||||
forms[1]['platform'] = amo.PLATFORM_LINUX.id
|
||||
self.client.post(self.url, self.formset(*forms, prefix='files'))
|
||||
assert File.objects.no_cache().get(pk=bsd.pk).platform == (
|
||||
assert File.objects.get(pk=bsd.pk).platform == (
|
||||
amo.PLATFORM_LINUX.id)
|
||||
forms = self.client.get(self.url).context['file_form'].forms
|
||||
choices = self.get_platforms(forms[1])
|
||||
|
@ -945,7 +945,7 @@ class TestPlatformSearchEngine(TestVersionEditMixin, TestCase):
|
|||
approvalnotes='yy')
|
||||
response = self.client.post(self.url, dd)
|
||||
assert response.status_code == 302
|
||||
file_ = Version.objects.no_cache().get(id=42352).files.all()[0]
|
||||
file_ = Version.objects.get(id=42352).files.all()[0]
|
||||
assert amo.PLATFORM_ALL.id == file_.platform
|
||||
|
||||
|
||||
|
|
|
@ -1062,9 +1062,7 @@ def version_edit(request, addon_id, addon, version_id):
|
|||
amo.permissions.REVIEWS_ADMIN)
|
||||
|
||||
if addon.accepts_compatible_apps():
|
||||
# We should be in no-caching land but this one stays cached for some
|
||||
# reason.
|
||||
qs = version.apps.all().no_cache()
|
||||
qs = version.apps.all()
|
||||
compat_form = forms.CompatFormSet(
|
||||
request.POST or None, queryset=qs,
|
||||
form_kwargs={'version': version})
|
||||
|
|
|
@ -35,7 +35,6 @@ def cleanup_extracted_file():
|
|||
def cleanup_validation_results():
|
||||
"""Will remove all validation results. Used when the validator is
|
||||
upgraded and results may no longer be relevant."""
|
||||
# With a large enough number of objects not using no_cache() tracebacks
|
||||
all = FileValidation.objects.no_cache().all()
|
||||
all = FileValidation.objects.all()
|
||||
log.info('Removing %s old validation results.' % (all.count()))
|
||||
all.delete()
|
||||
|
|
|
@ -28,7 +28,7 @@ import olympia.core.logger
|
|||
from olympia import amo
|
||||
from olympia.lib.cache import memoize
|
||||
from olympia.amo.decorators import use_master
|
||||
from olympia.amo.models import ModelBase, OnChangeMixin, UncachedManagerBase
|
||||
from olympia.amo.models import ModelBase, OnChangeMixin, ManagerBase
|
||||
from olympia.amo.storage_utils import copy_stored_file, move_stored_file
|
||||
from olympia.amo.templatetags.jinja_helpers import (
|
||||
absolutify, urlparams, user_media_path, user_media_url)
|
||||
|
@ -342,7 +342,7 @@ class File(OnChangeMixin, ModelBase):
|
|||
|
||||
_get_localepicker = re.compile('^locale browser ([\w\-_]+) (.*)$', re.M)
|
||||
|
||||
@memoize(prefix='localepicker', time=None)
|
||||
@memoize(prefix='localepicker', timeout=None)
|
||||
def get_localepicker(self):
|
||||
"""
|
||||
For a file that is part of a language pack, extract
|
||||
|
@ -601,7 +601,7 @@ class FileUpload(ModelBase):
|
|||
version = models.CharField(max_length=255, null=True)
|
||||
addon = models.ForeignKey('addons.Addon', null=True)
|
||||
|
||||
objects = UncachedManagerBase()
|
||||
objects = ManagerBase()
|
||||
|
||||
class Meta(ModelBase.Meta):
|
||||
db_table = 'file_uploads'
|
||||
|
|
|
@ -47,7 +47,7 @@ class TestWebextExtractPermissions(UploadTest):
|
|||
|
||||
call_command('extract_permissions')
|
||||
|
||||
file_ = File.objects.no_cache().get(id=file_.id)
|
||||
file_ = File.objects.get(id=file_.id)
|
||||
assert WebextPermission.objects.get(file=file_)
|
||||
permissions_list = file_.webext_permissions_list
|
||||
assert len(permissions_list) == 8
|
||||
|
@ -74,7 +74,7 @@ class TestWebextExtractPermissions(UploadTest):
|
|||
|
||||
call_command('extract_permissions', force=True)
|
||||
|
||||
file_ = File.objects.no_cache().get(id=file_.id)
|
||||
file_ = File.objects.get(id=file_.id)
|
||||
assert WebextPermission.objects.get(file=file_)
|
||||
assert len(file_.webext_permissions_list) == 8
|
||||
|
||||
|
@ -135,7 +135,7 @@ class TestWebextUpdateDescriptions(TestCase):
|
|||
|
||||
def _check_locales(self):
|
||||
with translation.override('fr'):
|
||||
assert WebextPermissionDescription.objects.no_cache().get(
|
||||
assert WebextPermissionDescription.objects.get(
|
||||
name='bookmarks').description == u'Réad n wríte le bookmarks'
|
||||
# There wasn't any French l10n for this perm; so en fallback.
|
||||
assert WebextPermissionDescription.objects.get(
|
||||
|
@ -144,7 +144,7 @@ class TestWebextUpdateDescriptions(TestCase):
|
|||
name='tabs').description == u'Accéder browser onglets'
|
||||
|
||||
with translation.override('de'):
|
||||
assert WebextPermissionDescription.objects.no_cache().get(
|
||||
assert WebextPermissionDescription.objects.get(
|
||||
name='bookmarks').description == u'Eich bin bookmark'
|
||||
# There wasn't any German l10n for this perm; so en fallback.
|
||||
assert WebextPermissionDescription.objects.get(
|
||||
|
@ -153,7 +153,7 @@ class TestWebextUpdateDescriptions(TestCase):
|
|||
assert WebextPermissionDescription.objects.get(
|
||||
name='tabs').description == u'Access browser tabs'
|
||||
with translation.override('zh-CN'):
|
||||
assert WebextPermissionDescription.objects.no_cache().get(
|
||||
assert WebextPermissionDescription.objects.get(
|
||||
name='bookmarks').description == u'讀取並修改書籤'
|
||||
# There wasn't any Chinese l10n for this perm; so en fallback.
|
||||
assert WebextPermissionDescription.objects.get(
|
||||
|
|
|
@ -240,7 +240,7 @@ class TestFile(TestCase, amo.tests.AMOPaths):
|
|||
def test_addon(self):
|
||||
f = File.objects.get(pk=67442)
|
||||
addon_id = f.version.addon_id
|
||||
addon = Addon.objects.no_cache().get(pk=addon_id)
|
||||
addon = Addon.objects.get(pk=addon_id)
|
||||
addon.update(status=amo.STATUS_DELETED)
|
||||
assert f.addon.id == addon_id
|
||||
|
||||
|
|
|
@ -8,13 +8,13 @@ from django.views.decorators.http import condition
|
|||
import olympia.core.logger
|
||||
|
||||
from olympia.access import acl
|
||||
from olympia.lib.cache import Message, Token
|
||||
from olympia.amo.decorators import json_view
|
||||
from olympia.amo.urlresolvers import reverse
|
||||
from olympia.amo.utils import HttpResponseSendFile, render, urlparams
|
||||
from olympia.files.decorators import (
|
||||
compare_file_view, etag, file_view, file_view_token, last_modified)
|
||||
from olympia.files.file_viewer import extract_file
|
||||
from olympia.lib.cache import Message, Token
|
||||
|
||||
from . import forms
|
||||
|
||||
|
|
|
@ -94,7 +94,6 @@
|
|||
{% endfor -%}
|
||||
{%- endif -%}
|
||||
{%- if new_api %}
|
||||
|
||||
{%- if addon.contributions -%}
|
||||
<contribution_data>
|
||||
<meet_developers>
|
||||
|
|
|
@ -19,8 +19,6 @@ from django.utils.translation import get_language, ugettext, ugettext_lazy as _
|
|||
|
||||
import waffle
|
||||
|
||||
from caching.base import cached_with
|
||||
|
||||
import olympia.core.logger
|
||||
|
||||
from olympia import amo, legacy_api
|
||||
|
@ -301,7 +299,6 @@ def guid_search(request, api_version, guids):
|
|||
try:
|
||||
# Only search through public (and not disabled) add-ons.
|
||||
addon = Addon.objects.public().get(guid=guid)
|
||||
|
||||
except Addon.DoesNotExist:
|
||||
addons_xml[key] = ''
|
||||
|
||||
|
@ -388,16 +385,17 @@ class SearchView(APIView):
|
|||
.filter_query_string(query)
|
||||
[:limit])
|
||||
|
||||
results = []
|
||||
|
||||
total = qs.count()
|
||||
|
||||
results = []
|
||||
for addon in qs:
|
||||
compat_version = find_compatible_version(
|
||||
addon, app_id, params['version'], params['platform'],
|
||||
compat_mode)
|
||||
# Specific case for Personas (bug 990768): if we search providing
|
||||
# the Persona addon type (9), then don't look for a compatible
|
||||
# version.
|
||||
# Specific case for Personas (bug 990768): if we search
|
||||
# providing the Persona addon type (9), then don't look for a
|
||||
# compatible version.
|
||||
if compat_version or addon_type == '9':
|
||||
addon.compat_version = compat_version
|
||||
results.append(addon)
|
||||
|
@ -439,8 +437,8 @@ class ListView(APIView):
|
|||
limit=10, platform='ALL', version=None,
|
||||
compat_mode='strict'):
|
||||
"""
|
||||
Find a list of new or featured add-ons. Filtering is done in Python
|
||||
for cache-friendliness and to avoid heavy queries.
|
||||
Find a list of new or featured add-ons. Filtering is done in Python
|
||||
to avoid heavy queries.
|
||||
"""
|
||||
limit = min(MAX_LIMIT, int(limit))
|
||||
APP, platform = self.request.APP, platform.lower()
|
||||
|
@ -471,14 +469,8 @@ class ListView(APIView):
|
|||
args = (addon_type, limit, APP, platform, version, compat_mode,
|
||||
shuffle)
|
||||
|
||||
def f():
|
||||
return self._process(addons, *args)
|
||||
|
||||
return cached_with(addons, f, map(force_bytes, args))
|
||||
|
||||
def _process(self, addons, *args):
|
||||
return self.render('legacy_api/list.xml',
|
||||
{'addons': addon_filter(addons, *args)})
|
||||
{'addons': addon_filter(addons.all(), *args)})
|
||||
|
||||
def render_json(self, context):
|
||||
return json.dumps([addon_to_dict(a) for a in context['addons']],
|
||||
|
|
|
@ -30,7 +30,7 @@ class TestModuleAdmin(TestCase):
|
|||
modules = qs.values_list('module', flat=True)
|
||||
assert set(modules) == set(registry.keys())
|
||||
|
||||
qs = DiscoveryModule.objects.no_cache().filter(app=1)
|
||||
qs = DiscoveryModule.objects.filter(app=1)
|
||||
assert qs.count() == 0
|
||||
|
||||
# All our modules get added.
|
||||
|
|
|
@ -90,7 +90,6 @@ def pane_promos(request, version, platform, compat_mode=None):
|
|||
|
||||
@non_atomic_requests
|
||||
def pane_more_addons(request, section, version, platform, compat_mode=None):
|
||||
|
||||
if not compat_mode:
|
||||
compat_mode = get_compat_mode(version)
|
||||
|
||||
|
@ -103,7 +102,9 @@ def pane_more_addons(request, section, version, platform, compat_mode=None):
|
|||
ctx = {'featured_addons': from_api('featured')}
|
||||
elif section == 'up-and-coming':
|
||||
ctx = {'up_and_coming': from_api('hotness')}
|
||||
return render(request, 'legacy_discovery/more_addons.html', ctx)
|
||||
|
||||
content = render(request, 'legacy_discovery/more_addons.html', ctx)
|
||||
return content
|
||||
|
||||
|
||||
def get_modules(request, platform, version):
|
||||
|
@ -145,10 +146,9 @@ def api_view(request, platform, version, list_type, api_version=1.5,
|
|||
def module_admin(request):
|
||||
APP = request.APP
|
||||
# Custom sorting to drop ordering=NULL objects to the bottom.
|
||||
with amo.models.skip_cache():
|
||||
qs = DiscoveryModule.objects.raw("""
|
||||
SELECT * from discovery_modules WHERE app_id = %s
|
||||
ORDER BY ordering IS NULL, ordering""", [APP.id])
|
||||
qs = DiscoveryModule.objects.raw("""
|
||||
SELECT * from discovery_modules WHERE app_id = %s
|
||||
ORDER BY ordering IS NULL, ordering""", [APP.id])
|
||||
qs.ordered = True # The formset looks for this.
|
||||
_sync_db_and_registry(qs, APP.id)
|
||||
|
||||
|
|
|
@ -5,9 +5,8 @@ import re
|
|||
import uuid
|
||||
from contextlib import contextmanager
|
||||
|
||||
from django.core.cache import cache, _create_cache
|
||||
from django.core.cache.backends.base import DEFAULT_TIMEOUT, BaseCache
|
||||
from django.core import cache as django_cache
|
||||
from django.core.cache import cache, caches, _create_cache
|
||||
from django.utils import encoding, translation
|
||||
from django.conf import settings
|
||||
|
||||
|
@ -32,7 +31,7 @@ def cache_get_or_set(key, default, timeout=DEFAULT_TIMEOUT, version=None):
|
|||
|
||||
Return the value of the key stored or retrieved.
|
||||
|
||||
Backport from Django 1.11
|
||||
Backport from Django 1.11.
|
||||
"""
|
||||
val = cache.get(key, version=version)
|
||||
|
||||
|
@ -68,43 +67,24 @@ def memoize_key(prefix, *args, **kwargs):
|
|||
prefix, key.hexdigest())
|
||||
|
||||
|
||||
def memoize_get(prefix, *args, **kwargs):
|
||||
"""
|
||||
Returns the content of the cache.
|
||||
|
||||
:param prefix: a prefix for the key in memcache
|
||||
:type prefix: string
|
||||
:param args: arguments to be str()'d to form the key
|
||||
:type args: list
|
||||
:param kwargs: arguments to be str()'d to form the key
|
||||
:type kwargs: list
|
||||
"""
|
||||
return cache.get(memoize_key(prefix, *args, **kwargs))
|
||||
|
||||
|
||||
def memoize(prefix, time=60):
|
||||
def memoize(prefix, timeout=60):
|
||||
"""
|
||||
A simple decorator that caches into memcache, using a simple
|
||||
key based on stringing args and kwargs.
|
||||
|
||||
Arguments to the method must be easily and consistently serializable
|
||||
using str(..) otherwise the cache key will be inconsistent.
|
||||
|
||||
:param prefix: a prefix for the key in memcache
|
||||
:type prefix: string
|
||||
:param time: number of seconds to cache the key for, default 60 seconds
|
||||
:type time: integer
|
||||
:param timeout: number of seconds to cache the key for, default 60 seconds
|
||||
:type timeout: integer
|
||||
"""
|
||||
def decorator(func):
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
def wrapped_func():
|
||||
return func(*args, **kwargs)
|
||||
key = memoize_key(prefix, *args, **kwargs)
|
||||
data = cache.get(key)
|
||||
if data is not None:
|
||||
return data
|
||||
data = func(*args, **kwargs)
|
||||
cache.set(key, data, time)
|
||||
return data
|
||||
return cache_get_or_set(key, wrapped_func, timeout=timeout)
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
|
@ -222,8 +202,8 @@ class CacheStatTracker(BaseCache):
|
|||
|
||||
|
||||
@contextmanager
|
||||
def assert_cache_requests(num):
|
||||
cache_using = django_cache.caches['default']
|
||||
def assert_cache_requests(num, alias='default'):
|
||||
cache_using = caches[alias]
|
||||
cache_using.clear_log()
|
||||
|
||||
yield
|
||||
|
@ -231,5 +211,4 @@ def assert_cache_requests(num):
|
|||
executed = len(cache_using.requests_log)
|
||||
|
||||
assert executed == num, "%d requests executed, %d expected" % (
|
||||
executed, num,
|
||||
)
|
||||
executed, num)
|
||||
|
|
|
@ -36,11 +36,7 @@ def index_objects(ids, model, extract_func, index=None, transforms=None,
|
|||
if transforms is None:
|
||||
transforms = []
|
||||
|
||||
if hasattr(objects, 'no_cache'):
|
||||
qs = objects.no_cache()
|
||||
else:
|
||||
qs = objects
|
||||
qs = qs.filter(id__in=ids)
|
||||
qs = objects.filter(id__in=ids)
|
||||
for t in transforms:
|
||||
qs = qs.transform(t)
|
||||
|
||||
|
|
|
@ -992,10 +992,6 @@ MINIFY_BUNDLES = {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
# Caching
|
||||
CACHE_MACHINE_ENABLED = True
|
||||
|
||||
# Prefix for cache keys (will prevent collisions when running parallel copies)
|
||||
CACHE_PREFIX = 'amo:%s:' % build_id
|
||||
KEY_PREFIX = CACHE_PREFIX
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from django.test import TestCase
|
||||
from django.test.utils import override_settings
|
||||
from django.utils import translation
|
||||
from django.core.cache import cache
|
||||
|
||||
from unittest import TestCase
|
||||
from olympia.lib.cache import (
|
||||
cache_get_or_set, make_key, Message, Token, memoize, memoize_get,
|
||||
memoize_key)
|
||||
Message, Token, memoize, memoize_key, cache_get_or_set,
|
||||
make_key)
|
||||
|
||||
|
||||
@override_settings(KEY_PREFIX='amo:test:')
|
||||
|
@ -61,7 +61,8 @@ def test_memoize():
|
|||
def add(*args):
|
||||
return sum(args)
|
||||
|
||||
assert add(1, 2) == memoize_get('f', 1, 2)
|
||||
cache_key = memoize_key('f', 1, 2)
|
||||
assert add(1, 2) == cache.get(cache_key)
|
||||
|
||||
|
||||
class TestToken(TestCase):
|
||||
|
|
|
@ -3,8 +3,6 @@ from django.db import models
|
|||
from django.db.models import Q
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
import caching.base as caching
|
||||
|
||||
import olympia.core.logger
|
||||
|
||||
from olympia import activity, amo
|
||||
|
@ -44,7 +42,7 @@ class WithoutRepliesRatingManager(ManagerBase):
|
|||
return qs.filter(reply_to__isnull=True)
|
||||
|
||||
|
||||
class RatingQuerySet(caching.CachingQuerySet):
|
||||
class RatingQuerySet(models.QuerySet):
|
||||
"""
|
||||
A queryset modified for soft deletion.
|
||||
"""
|
||||
|
|
|
@ -183,7 +183,7 @@ class RatingSerializer(BaseRatingSerializer):
|
|||
raise serializers.ValidationError(
|
||||
ugettext(u'You can\'t leave a review on your own add-on.'))
|
||||
|
||||
rating_exists_on_this_version = Rating.objects.no_cache().filter(
|
||||
rating_exists_on_this_version = Rating.objects.filter(
|
||||
addon=data['addon'], user=data['user'],
|
||||
version=data['version']).using('default').exists()
|
||||
if rating_exists_on_this_version:
|
||||
|
|
|
@ -5,7 +5,7 @@ import olympia.core.logger
|
|||
from olympia.addons.models import Addon
|
||||
from olympia.amo.celery import task
|
||||
from olympia.amo.decorators import write
|
||||
from olympia.lib.cache import cache_get_or_set, make_key
|
||||
from olympia.lib.cache import cache_get_or_set
|
||||
|
||||
from .models import GroupedRating, Rating
|
||||
|
||||
|
@ -23,7 +23,7 @@ def update_denorm(*pairs, **kw):
|
|||
log.info('[%s@%s] Updating review denorms.' %
|
||||
(len(pairs), update_denorm.rate_limit))
|
||||
for addon, user in pairs:
|
||||
reviews = list(Rating.without_replies.all().no_cache()
|
||||
reviews = list(Rating.without_replies.all()
|
||||
.filter(addon=addon, user=user).order_by('created'))
|
||||
if not reviews:
|
||||
continue
|
||||
|
@ -48,14 +48,14 @@ def addon_rating_aggregates(addons, **kw):
|
|||
# The following returns something like
|
||||
# [{'rating': 2.0, 'addon': 7L, 'count': 5},
|
||||
# {'rating': 3.75, 'addon': 6L, 'count': 8}, ...]
|
||||
qs = (Rating.without_replies.all().no_cache()
|
||||
qs = (Rating.without_replies.all()
|
||||
.filter(addon__in=addons, is_latest=True)
|
||||
.values('addon') # Group by addon id.
|
||||
.annotate(rating=Avg('rating'), count=Count('addon')) # Aggregates.
|
||||
.order_by()) # Reset order by so that `created` is not included.
|
||||
stats = {x['addon']: (x['rating'], x['count']) for x in qs}
|
||||
|
||||
text_qs = (Rating.without_replies.all().no_cache()
|
||||
text_qs = (Rating.without_replies.all()
|
||||
.filter(addon__in=addons, is_latest=True)
|
||||
.exclude(body=None)
|
||||
.values('addon') # Group by addon id.
|
||||
|
@ -84,15 +84,14 @@ def addon_bayesian_rating(*addons, **kw):
|
|||
log.info('[%s@%s] Updating bayesian ratings.' %
|
||||
(len(addons), addon_bayesian_rating.rate_limit))
|
||||
|
||||
avg = cache_get_or_set(
|
||||
make_key('task.bayes.avg'), addon_aggregates, 60 * 60 * 60)
|
||||
avg = cache_get_or_set('task.bayes.avg', addon_aggregates, 60 * 60 * 60)
|
||||
# Rating can be NULL in the DB, so don't update it if it's not there.
|
||||
if avg['rating'] is None:
|
||||
return
|
||||
|
||||
mc = avg['reviews'] * avg['rating']
|
||||
|
||||
for addon in Addon.objects.no_cache().filter(id__in=addons):
|
||||
for addon in Addon.objects.filter(id__in=addons):
|
||||
if addon.average_rating is None:
|
||||
# Ignoring addons with no average rating.
|
||||
continue
|
||||
|
|
|
@ -1346,9 +1346,6 @@ class TestRatingViewSetGet(TestCase):
|
|||
data = json.loads(response.content)
|
||||
assert data == {'detail': 'version parameter should be an integer.'}
|
||||
|
||||
# settings_test sets CACHE_COUNT_TIMEOUT to -1 and it's too late to
|
||||
# override it, so instead mock the TIMEOUT property in cache-machine.
|
||||
@mock.patch('caching.config.TIMEOUT', 300)
|
||||
def test_get_then_post_then_get_any_caching_is_cleared(self):
|
||||
"""Make sure there is no overzealous caching going on when requesting
|
||||
the list of reviews for a given user+addon+version combination.
|
||||
|
|
|
@ -44,7 +44,7 @@ class Command(BaseCommand):
|
|||
addon__status__in=(amo.STATUS_PUBLIC, amo.STATUS_NOMINATED),
|
||||
files__status=amo.STATUS_AWAITING_REVIEW,
|
||||
files__is_webextension=True)
|
||||
.no_cache().order_by('nomination', 'created').distinct())
|
||||
.order_by('nomination', 'created').distinct())
|
||||
|
||||
def handle(self, *args, **options):
|
||||
"""Command entry point."""
|
||||
|
|
|
@ -17,7 +17,7 @@ from olympia import amo
|
|||
from olympia.abuse.models import AbuseReport
|
||||
from olympia.access import acl
|
||||
from olympia.addons.models import Addon, Persona
|
||||
from olympia.amo.models import ManagerBase, ModelBase, skip_cache
|
||||
from olympia.amo.models import ManagerBase, ModelBase
|
||||
from olympia.amo.templatetags.jinja_helpers import absolutify
|
||||
from olympia.amo.urlresolvers import reverse
|
||||
from olympia.amo.utils import cache_ns_key, send_mail
|
||||
|
@ -539,7 +539,7 @@ class ReviewerScore(ModelBase):
|
|||
if val is not None:
|
||||
return val
|
||||
|
||||
val = (ReviewerScore.objects.no_cache().filter(user=user)
|
||||
val = (ReviewerScore.objects.filter(user=user)
|
||||
.aggregate(total=Sum('score'))
|
||||
.values())[0]
|
||||
if val is None:
|
||||
|
@ -556,7 +556,7 @@ class ReviewerScore(ModelBase):
|
|||
if val is not None:
|
||||
return val
|
||||
|
||||
val = ReviewerScore.objects.no_cache().filter(user=user)
|
||||
val = ReviewerScore.objects.filter(user=user)
|
||||
if addon_type is not None:
|
||||
val.filter(addon__type=addon_type)
|
||||
|
||||
|
@ -582,8 +582,7 @@ class ReviewerScore(ModelBase):
|
|||
GROUP BY `addons`.`addontype_id`
|
||||
ORDER BY `total` DESC
|
||||
"""
|
||||
with skip_cache():
|
||||
val = list(ReviewerScore.objects.raw(sql, [user.id]))
|
||||
val = list(ReviewerScore.objects.raw(sql, [user.id]))
|
||||
cache.set(key, val, None)
|
||||
return val
|
||||
|
||||
|
@ -608,8 +607,7 @@ class ReviewerScore(ModelBase):
|
|||
GROUP BY `addons`.`addontype_id`
|
||||
ORDER BY `total` DESC
|
||||
"""
|
||||
with skip_cache():
|
||||
val = list(ReviewerScore.objects.raw(sql, [user.id, since]))
|
||||
val = list(ReviewerScore.objects.raw(sql, [user.id, since]))
|
||||
cache.set(key, val, 3600)
|
||||
return val
|
||||
|
||||
|
|
|
@ -2112,8 +2112,7 @@ class TestContentReviewQueue(QueueTest):
|
|||
AutoApprovalSummary.objects.create(
|
||||
version=addon4.current_version,
|
||||
verdict=amo.AUTO_APPROVED, confirmed=True)
|
||||
assert not AddonApprovalsCounter.objects.no_cache().filter(
|
||||
addon=addon4).exists()
|
||||
assert not AddonApprovalsCounter.objects.filter(addon=addon4).exists()
|
||||
|
||||
# Addons with no last_content_review date should be first, ordered by
|
||||
# their creation date, older first.
|
||||
|
|
|
@ -104,12 +104,12 @@ def _get_themes(request, reviewer, flagged=False, rereview=False):
|
|||
num, themes, locks = _get_rereview_themes(reviewer)
|
||||
else:
|
||||
# Pending and flagged themes.
|
||||
locks = ThemeLock.objects.no_cache().filter(
|
||||
locks = ThemeLock.objects.filter(
|
||||
reviewer=reviewer, theme__addon__status=status)
|
||||
num, themes = _calc_num_themes_checkout(locks)
|
||||
if themes:
|
||||
return themes
|
||||
themes = Persona.objects.no_cache().filter(
|
||||
themes = Persona.objects.filter(
|
||||
addon__status=status, themelock=None)
|
||||
|
||||
# Don't allow self-reviews.
|
||||
|
@ -141,7 +141,7 @@ def _get_themes(request, reviewer, flagged=False, rereview=False):
|
|||
locks = expired_locks
|
||||
|
||||
if rereview:
|
||||
return (RereviewQueueTheme.objects.no_cache()
|
||||
return (RereviewQueueTheme.objects
|
||||
.filter(theme__themelock__reviewer=reviewer)
|
||||
.exclude(theme__addon__status=amo.STATUS_REJECTED))
|
||||
|
||||
|
@ -247,7 +247,7 @@ def _calc_num_themes_checkout(locks):
|
|||
|
||||
def _get_rereview_themes(reviewer):
|
||||
"""Check out re-uploaded themes."""
|
||||
locks = (ThemeLock.objects.select_related().no_cache()
|
||||
locks = (ThemeLock.objects.select_related()
|
||||
.filter(reviewer=reviewer,
|
||||
theme__rereviewqueuetheme__isnull=False)
|
||||
.exclude(theme__addon__status=amo.STATUS_REJECTED))
|
||||
|
@ -256,7 +256,7 @@ def _get_rereview_themes(reviewer):
|
|||
if updated_locks:
|
||||
locks = updated_locks
|
||||
|
||||
themes = (RereviewQueueTheme.objects.no_cache()
|
||||
themes = (RereviewQueueTheme.objects
|
||||
.filter(theme__addon__isnull=False, theme__themelock=None)
|
||||
.exclude(theme__addon__status=amo.STATUS_REJECTED))
|
||||
return num, themes, locks
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
from django.db import models
|
||||
from django_extensions.db.fields.json import JSONField
|
||||
|
||||
import caching.base
|
||||
|
||||
from olympia.amo.models import SearchMixin
|
||||
|
||||
|
||||
|
@ -137,13 +135,11 @@ class ThemeUpdateCountBulk(models.Model):
|
|||
db_table = 'theme_update_counts_bulk'
|
||||
|
||||
|
||||
class GlobalStat(caching.base.CachingMixin, models.Model):
|
||||
class GlobalStat(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
count = models.IntegerField()
|
||||
date = models.DateField()
|
||||
|
||||
objects = caching.base.CachingManager()
|
||||
|
||||
class Meta:
|
||||
db_table = 'global_stats'
|
||||
unique_together = ('name', 'date')
|
||||
|
|
|
@ -21,10 +21,10 @@ class TestGlobalStats(TestCase):
|
|||
date = datetime.date(2009, 6, 1)
|
||||
job = 'addon_total_downloads'
|
||||
|
||||
assert GlobalStat.objects.no_cache().filter(
|
||||
assert GlobalStat.objects.filter(
|
||||
date=date, name=job).count() == 0
|
||||
tasks.update_global_totals(job, date)
|
||||
assert len(GlobalStat.objects.no_cache().filter(
|
||||
assert len(GlobalStat.objects.filter(
|
||||
date=date, name=job)) == 1
|
||||
|
||||
def test_count_stats_for_date(self):
|
||||
|
@ -45,14 +45,14 @@ class TestGlobalStats(TestCase):
|
|||
date = datetime.date.today()
|
||||
job = 'addon_count_new'
|
||||
tasks.update_global_totals(job, date)
|
||||
global_stat = GlobalStat.objects.no_cache().get(date=date, name=job)
|
||||
global_stat = GlobalStat.objects.get(date=date, name=job)
|
||||
assert global_stat.count == 1
|
||||
|
||||
# Should still work if the date is passed as a datetime string (what
|
||||
# celery serialization does).
|
||||
job = 'version_count_new'
|
||||
tasks.update_global_totals(job, datetime.datetime.now().isoformat())
|
||||
global_stat = GlobalStat.objects.no_cache().get(date=date, name=job)
|
||||
global_stat = GlobalStat.objects.get(date=date, name=job)
|
||||
assert global_stat.count == 1
|
||||
|
||||
def test_through_cron(self):
|
||||
|
@ -78,13 +78,11 @@ class TestGlobalStats(TestCase):
|
|||
cron.update_global_totals()
|
||||
|
||||
job = 'addon_count_new'
|
||||
global_stat = GlobalStat.objects.no_cache().get(
|
||||
date=yesterday, name=job)
|
||||
global_stat = GlobalStat.objects.get(date=yesterday, name=job)
|
||||
assert global_stat.count == 1
|
||||
|
||||
job = 'version_count_new'
|
||||
global_stat = GlobalStat.objects.no_cache().get(
|
||||
date=yesterday, name=job)
|
||||
global_stat = GlobalStat.objects.get(date=yesterday, name=job)
|
||||
assert global_stat.count == 1
|
||||
|
||||
def test_input(self):
|
||||
|
|
|
@ -444,7 +444,7 @@ _KEYS = {
|
|||
_CACHED_KEYS = sorted(_KEYS.values())
|
||||
|
||||
|
||||
@memoize(prefix='global_stats', time=60 * 60)
|
||||
@memoize(prefix='global_stats', timeout=60 * 60)
|
||||
def _site_query(period, start, end, field=None, request=None):
|
||||
with connection.cursor() as cursor:
|
||||
# Let MySQL make this fast. Make sure we prevent SQL injection with the
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
from django.db import connections, models, router
|
||||
from django.db.models.deletion import Collector
|
||||
from django.utils.encoding import force_text
|
||||
|
||||
import bleach
|
||||
|
||||
|
@ -105,16 +104,6 @@ class Translation(ModelBase):
|
|||
|
||||
delete.alters_data = True
|
||||
|
||||
@classmethod
|
||||
def _cache_key(cls, pk, db):
|
||||
# Hard-coding the class name here so that subclasses don't try to cache
|
||||
# themselves under something like "o:translations.purifiedtranslation".
|
||||
#
|
||||
# Like in ModelBase, we avoid putting the real db in the key because it
|
||||
# does us more harm than good.
|
||||
key_parts = ('o', 'translations.translation', pk, 'default')
|
||||
return ':'.join(map(force_text, key_parts))
|
||||
|
||||
@classmethod
|
||||
def new(cls, string, locale, id=None):
|
||||
"""
|
||||
|
|
|
@ -676,17 +676,3 @@ def test_comparison_with_lazy():
|
|||
lazy_u = lazy(lambda x: x, unicode)
|
||||
x == lazy_u('xxx')
|
||||
lazy_u('xxx') == x
|
||||
|
||||
|
||||
def test_cache_key():
|
||||
# Test that we are not taking the db into account when building our
|
||||
# cache keys for django-cache-machine. See bug 928881.
|
||||
assert Translation._cache_key(1, 'default') == (
|
||||
Translation._cache_key(1, 'slave'))
|
||||
|
||||
# Test that we are using the same cache no matter what Translation class
|
||||
# we use.
|
||||
assert PurifiedTranslation._cache_key(1, 'default') == (
|
||||
Translation._cache_key(1, 'default'))
|
||||
assert LinkifiedTranslation._cache_key(1, 'default') == (
|
||||
Translation._cache_key(1, 'default'))
|
||||
|
|
|
@ -1,29 +1,29 @@
|
|||
from django.db import models
|
||||
|
||||
from olympia.amo.models import UncachedManagerBase, UncachedModelBase
|
||||
from olympia.amo.models import ManagerBase, ModelBase
|
||||
from olympia.translations.fields import (
|
||||
LinkifiedField, PurifiedField, TranslatedField, save_signal)
|
||||
|
||||
|
||||
class TranslatedModel(UncachedModelBase):
|
||||
class TranslatedModel(ModelBase):
|
||||
name = TranslatedField()
|
||||
description = TranslatedField()
|
||||
default_locale = models.CharField(max_length=10)
|
||||
no_locale = TranslatedField(require_locale=False)
|
||||
|
||||
objects = UncachedManagerBase()
|
||||
objects = ManagerBase()
|
||||
|
||||
|
||||
models.signals.pre_save.connect(save_signal, sender=TranslatedModel,
|
||||
dispatch_uid='testapp_translatedmodel')
|
||||
|
||||
|
||||
class UntranslatedModel(UncachedModelBase):
|
||||
class UntranslatedModel(ModelBase):
|
||||
"""Make sure nothing is broken when a model doesn't have translations."""
|
||||
number = models.IntegerField()
|
||||
|
||||
|
||||
class FancyModel(UncachedModelBase):
|
||||
class FancyModel(ModelBase):
|
||||
"""Mix it up with purified and linkified fields."""
|
||||
purified = PurifiedField()
|
||||
linkified = LinkifiedField()
|
||||
|
|
|
@ -360,7 +360,7 @@ class UserProfile(OnChangeMixin, ModelBase, AbstractBaseUser):
|
|||
self.addonuser_set.filter(
|
||||
role__in=[amo.AUTHOR_ROLE_OWNER, amo.AUTHOR_ROLE_DEV],
|
||||
listed=True,
|
||||
addon__status=amo.STATUS_PUBLIC).no_cache().exists())
|
||||
addon__status=amo.STATUS_PUBLIC).exists())
|
||||
if is_public != pre:
|
||||
log.info('Updating %s.is_public from %s to %s' % (
|
||||
self.pk, pre, is_public))
|
||||
|
|
|
@ -10,7 +10,6 @@ from django.db import models
|
|||
from django.utils.functional import cached_property
|
||||
from django.utils.translation import ugettext
|
||||
|
||||
import caching.base
|
||||
import jinja2
|
||||
|
||||
from django_extensions.db.fields.json import JSONField
|
||||
|
@ -358,7 +357,7 @@ class Version(OnChangeMixin, ModelBase):
|
|||
def all_activity(self):
|
||||
from olympia.activity.models import VersionLog # yucky
|
||||
al = (VersionLog.objects.filter(version=self.id).order_by('created')
|
||||
.select_related('activity_log', 'version').no_cache())
|
||||
.select_related('activity_log', 'version'))
|
||||
return al
|
||||
|
||||
@property
|
||||
|
@ -549,11 +548,9 @@ class Version(OnChangeMixin, ModelBase):
|
|||
return
|
||||
|
||||
ids = set(v.id for v in versions)
|
||||
# FIXME: find out why we have no_cache() here and try to remove it.
|
||||
avs = (ApplicationsVersions.objects.filter(version__in=ids)
|
||||
.select_related('min', 'max')
|
||||
.no_cache())
|
||||
files = File.objects.filter(version__in=ids).no_cache()
|
||||
.select_related('min', 'max'))
|
||||
files = File.objects.filter(version__in=ids)
|
||||
|
||||
def rollup(xs):
|
||||
groups = sorted_groupby(xs, 'version_id')
|
||||
|
@ -578,7 +575,7 @@ class Version(OnChangeMixin, ModelBase):
|
|||
return
|
||||
|
||||
al = (VersionLog.objects.filter(version__in=ids).order_by('created')
|
||||
.select_related('activity_log', 'version').no_cache())
|
||||
.select_related('activity_log', 'version'))
|
||||
|
||||
def rollup(xs):
|
||||
groups = sorted_groupby(xs, 'version_id')
|
||||
|
@ -612,8 +609,6 @@ class Version(OnChangeMixin, ModelBase):
|
|||
nomination = nomination or datetime.datetime.now()
|
||||
# We need signal=False not to call update_status (which calls us).
|
||||
self.update(nomination=nomination, _signal=False)
|
||||
# But we need the cache to be flushed.
|
||||
Version.objects.invalidate(self)
|
||||
|
||||
def inherit_nomination(self, from_statuses=None):
|
||||
last_ver = (Version.objects.filter(addon=self.addon,
|
||||
|
@ -801,7 +796,6 @@ models.signals.post_delete.connect(
|
|||
|
||||
|
||||
class LicenseManager(ManagerBase):
|
||||
|
||||
def builtins(self, cc=False):
|
||||
return self.filter(
|
||||
builtin__gt=0, creative_commons=cc).order_by('builtin')
|
||||
|
@ -842,7 +836,7 @@ models.signals.pre_save.connect(
|
|||
save_signal, sender=License, dispatch_uid='license_translations')
|
||||
|
||||
|
||||
class ApplicationsVersions(caching.base.CachingMixin, models.Model):
|
||||
class ApplicationsVersions(models.Model):
|
||||
|
||||
application = models.PositiveIntegerField(choices=amo.APPS_CHOICES,
|
||||
db_column='application_id')
|
||||
|
@ -853,8 +847,6 @@ class ApplicationsVersions(caching.base.CachingMixin, models.Model):
|
|||
max = models.ForeignKey(AppVersion, db_column='max',
|
||||
related_name='max_set')
|
||||
|
||||
objects = caching.base.CachingManager()
|
||||
|
||||
class Meta:
|
||||
db_table = u'applications_versions'
|
||||
unique_together = (("application", "version"),)
|
||||
|
|
|
@ -149,7 +149,7 @@ class TestVersion(TestCase):
|
|||
assert version.files.count() == 1
|
||||
version.delete()
|
||||
|
||||
addon = Addon.objects.no_cache().get(pk=3615)
|
||||
addon = Addon.objects.get(pk=3615)
|
||||
assert not Version.objects.filter(addon=addon).exists()
|
||||
assert Version.unfiltered.filter(addon=addon).exists()
|
||||
assert version.files.count() == 1
|
||||
|
@ -162,7 +162,7 @@ class TestVersion(TestCase):
|
|||
assert version.files.count() == 1
|
||||
version.delete(hard=True)
|
||||
|
||||
addon = Addon.objects.no_cache().get(pk=3615)
|
||||
addon = Addon.objects.get(pk=3615)
|
||||
assert not Version.objects.filter(addon=addon).exists()
|
||||
assert not Version.unfiltered.filter(addon=addon).exists()
|
||||
assert version.files.count() == 0
|
||||
|
@ -226,7 +226,7 @@ class TestVersion(TestCase):
|
|||
file = File(platform=amo.PLATFORM_MAC.id, version=version)
|
||||
file.save()
|
||||
# The transform don't know bout my new files.
|
||||
version = Version.objects.no_cache().get(pk=81551)
|
||||
version = Version.objects.get(pk=81551)
|
||||
assert not version.is_allowed_upload()
|
||||
|
||||
def test_version_is_not_allowed_upload_full(self):
|
||||
|
|
|
@ -37,10 +37,6 @@ def do_removeuser(user, group):
|
|||
|
||||
# Doesn't actually check if the user was in the group or not.
|
||||
GroupUser.objects.filter(user=user, group=group).delete()
|
||||
# Help django-cache-machine invalidate its cache (it has issues with
|
||||
# M2Ms).
|
||||
Group.objects.invalidate(*user.groups.all())
|
||||
|
||||
except UserProfile.DoesNotExist:
|
||||
raise CommandError('User ({user}) does not exist.'.format(user=user))
|
||||
except Group.DoesNotExist:
|
||||
|
|
|
@ -5,21 +5,17 @@ from decimal import Decimal
|
|||
from django.conf import settings
|
||||
from django.db import models
|
||||
|
||||
import caching
|
||||
|
||||
from olympia import amo
|
||||
from olympia.amo.models import ModelBase
|
||||
from olympia.applications.models import AppVersion
|
||||
from olympia.files.models import File
|
||||
|
||||
|
||||
class Config(caching.base.CachingMixin, models.Model):
|
||||
class Config(models.Model):
|
||||
"""Sitewide settings."""
|
||||
key = models.CharField(max_length=255, primary_key=True)
|
||||
value = models.TextField()
|
||||
|
||||
objects = caching.base.CachingManager()
|
||||
|
||||
class Meta:
|
||||
db_table = u'config'
|
||||
|
||||
|
@ -38,7 +34,7 @@ def get_config(conf):
|
|||
try:
|
||||
return Config.objects.get(key=conf).value
|
||||
except Config.DoesNotExist:
|
||||
return
|
||||
return None
|
||||
|
||||
|
||||
def set_config(conf, value):
|
||||
|
|
Загрузка…
Ссылка в новой задаче