mirror of
https://github.com/pretix/pretix.git
synced 2026-05-06 15:24:02 +00:00
Cache access to cache object
This commit is contained in:
@@ -11,17 +11,19 @@ class NamespacedCache:
|
||||
def __init__(self, prefixkey: str, cache: str='default'):
|
||||
self.cache = caches[cache]
|
||||
self.prefixkey = prefixkey
|
||||
self._last_prefix = None
|
||||
|
||||
def _prefix_key(self, original_key: str) -> str:
|
||||
def _prefix_key(self, original_key: str, known_prefix=None) -> str:
|
||||
# Race conditions can happen here, but should be very very rare.
|
||||
# We could only handle this by going _really_ lowlevel using
|
||||
# memcached's `add` keyword instead of `set`.
|
||||
# See also:
|
||||
# https://code.google.com/p/memcached/wiki/NewProgrammingTricks#Namespacing
|
||||
prefix = self.cache.get(self.prefixkey)
|
||||
prefix = known_prefix or self.cache.get(self.prefixkey)
|
||||
if prefix is None:
|
||||
prefix = int(time.time())
|
||||
self.cache.set(self.prefixkey, prefix)
|
||||
self._last_prefix = prefix
|
||||
key = '%s:%d:%s' % (self.prefixkey, prefix, original_key)
|
||||
if len(key) > 200: # Hash long keys, as memcached has a length limit
|
||||
# TODO: Use a more efficient, non-cryptographic hash algorithm
|
||||
@@ -32,6 +34,7 @@ class NamespacedCache:
|
||||
return key.split(":", 2 + self.prefixkey.count(":"))[-1]
|
||||
|
||||
def clear(self) -> None:
|
||||
self._last_prefix = None
|
||||
try:
|
||||
prefix = self.cache.incr(self.prefixkey, 1)
|
||||
except ValueError:
|
||||
@@ -42,7 +45,7 @@ class NamespacedCache:
|
||||
return self.cache.set(self._prefix_key(key), value, timeout)
|
||||
|
||||
def get(self, key: str) -> str:
|
||||
return self.cache.get(self._prefix_key(key))
|
||||
return self.cache.get(self._prefix_key(key, known_prefix=self._last_prefix))
|
||||
|
||||
def get_many(self, keys: List[str]) -> Dict[str, str]:
|
||||
values = self.cache.get_many([self._prefix_key(key) for key in keys])
|
||||
|
||||
@@ -264,7 +264,7 @@ class Event(EventMixin, LoggedModel):
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
obj = super().save(*args, **kwargs)
|
||||
self.get_cache().clear()
|
||||
self.cache.clear()
|
||||
return obj
|
||||
|
||||
def get_plugins(self) -> "list[str]":
|
||||
@@ -281,6 +281,19 @@ class Event(EventMixin, LoggedModel):
|
||||
Django's built-in cache backends, but puts you into an isolated environment for
|
||||
this event, so you don't have to prefix your cache keys. In addition, the cache
|
||||
is being cleared every time the event or one of its related objects change.
|
||||
|
||||
.. deprecated:: 1.9
|
||||
Use the property ``cache`` instead.
|
||||
"""
|
||||
return self.cache
|
||||
|
||||
@cached_property
|
||||
def cache(self):
|
||||
"""
|
||||
Returns an :py:class:`ObjectRelatedCache` object. This behaves equivalent to
|
||||
Django's built-in cache backends, but puts you into an isolated environment for
|
||||
this event, so you don't have to prefix your cache keys. In addition, the cache
|
||||
is being cleared every time the event or one of its related objects change.
|
||||
"""
|
||||
from pretix.base.cache import ObjectRelatedCache
|
||||
|
||||
@@ -578,6 +591,16 @@ class SubEvent(EventMixin, LoggedModel):
|
||||
data.update({v.property.name: v.value for v in self.meta_values.select_related('property').all()})
|
||||
return data
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
super().delete(*args, **kwargs)
|
||||
if self.event:
|
||||
self.event.cache.clear()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super().save(*args, **kwargs)
|
||||
if self.event:
|
||||
self.event.cache.clear()
|
||||
|
||||
|
||||
def generate_invite_token():
|
||||
return get_random_string(length=32, allowed_chars=string.ascii_lowercase + string.digits)
|
||||
@@ -677,6 +700,16 @@ class EventMetaValue(LoggedModel):
|
||||
class Meta:
|
||||
unique_together = ('event', 'property')
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
super().delete(*args, **kwargs)
|
||||
if self.event:
|
||||
self.event.cache.clear()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super().save(*args, **kwargs)
|
||||
if self.event:
|
||||
self.event.cache.clear()
|
||||
|
||||
|
||||
class SubEventMetaValue(LoggedModel):
|
||||
"""
|
||||
@@ -697,3 +730,13 @@ class SubEventMetaValue(LoggedModel):
|
||||
|
||||
class Meta:
|
||||
unique_together = ('subevent', 'property')
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
super().delete(*args, **kwargs)
|
||||
if self.subevent:
|
||||
self.subevent.event.cache.clear()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super().save(*args, **kwargs)
|
||||
if self.subevent:
|
||||
self.subevent.event.cache.clear()
|
||||
|
||||
@@ -66,12 +66,12 @@ class ItemCategory(LoggedModel):
|
||||
def delete(self, *args, **kwargs):
|
||||
super().delete(*args, **kwargs)
|
||||
if self.event:
|
||||
self.event.get_cache().clear()
|
||||
self.event.cache.clear()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super().save(*args, **kwargs)
|
||||
if self.event:
|
||||
self.event.get_cache().clear()
|
||||
self.event.cache.clear()
|
||||
|
||||
@property
|
||||
def sortkey(self):
|
||||
@@ -104,6 +104,16 @@ class SubEventItem(models.Model):
|
||||
item = models.ForeignKey('Item', on_delete=models.CASCADE)
|
||||
price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
super().delete(*args, **kwargs)
|
||||
if self.subevent:
|
||||
self.subevent.event.cache.clear()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super().save(*args, **kwargs)
|
||||
if self.subevent:
|
||||
self.subevent.event.cache.clear()
|
||||
|
||||
|
||||
class SubEventItemVariation(models.Model):
|
||||
"""
|
||||
@@ -121,6 +131,16 @@ class SubEventItemVariation(models.Model):
|
||||
variation = models.ForeignKey('ItemVariation', on_delete=models.CASCADE)
|
||||
price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
super().delete(*args, **kwargs)
|
||||
if self.subevent:
|
||||
self.subevent.event.cache.clear()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super().save(*args, **kwargs)
|
||||
if self.subevent:
|
||||
self.subevent.event.cache.clear()
|
||||
|
||||
|
||||
class Item(LoggedModel):
|
||||
"""
|
||||
@@ -290,12 +310,12 @@ class Item(LoggedModel):
|
||||
def save(self, *args, **kwargs):
|
||||
super().save(*args, **kwargs)
|
||||
if self.event:
|
||||
self.event.get_cache().clear()
|
||||
self.event.cache.clear()
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
super().delete(*args, **kwargs)
|
||||
if self.event:
|
||||
self.event.get_cache().clear()
|
||||
self.event.cache.clear()
|
||||
|
||||
def tax(self, price=None, base_price_is='auto'):
|
||||
price = price if price is not None else self.default_price
|
||||
@@ -418,12 +438,12 @@ class ItemVariation(models.Model):
|
||||
def delete(self, *args, **kwargs):
|
||||
super().delete(*args, **kwargs)
|
||||
if self.item:
|
||||
self.item.event.get_cache().clear()
|
||||
self.item.event.cache.clear()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super().save(*args, **kwargs)
|
||||
if self.item:
|
||||
self.item.event.get_cache().clear()
|
||||
self.item.event.cache.clear()
|
||||
|
||||
def check_quotas(self, ignored_quotas=None, count_waitinglist=True, subevent=None, _cache=None) -> Tuple[int, int]:
|
||||
"""
|
||||
@@ -595,12 +615,12 @@ class Question(LoggedModel):
|
||||
def delete(self, *args, **kwargs):
|
||||
super().delete(*args, **kwargs)
|
||||
if self.event:
|
||||
self.event.get_cache().clear()
|
||||
self.event.cache.clear()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super().save(*args, **kwargs)
|
||||
if self.event:
|
||||
self.event.get_cache().clear()
|
||||
self.event.cache.clear()
|
||||
|
||||
@property
|
||||
def sortkey(self):
|
||||
@@ -719,13 +739,13 @@ class Quota(LoggedModel):
|
||||
def delete(self, *args, **kwargs):
|
||||
super().delete(*args, **kwargs)
|
||||
if self.event:
|
||||
self.event.get_cache().clear()
|
||||
self.event.cache.clear()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
clear_cache = kwargs.pop('clear_cache', True)
|
||||
super().save(*args, **kwargs)
|
||||
if self.event and clear_cache:
|
||||
self.event.get_cache().clear()
|
||||
self.event.cache.clear()
|
||||
|
||||
def rebuild_cache(self, now_dt=None):
|
||||
self.cached_availability_time = None
|
||||
|
||||
@@ -3,6 +3,7 @@ import string
|
||||
from django.core.validators import RegexValidator
|
||||
from django.db import models
|
||||
from django.utils.crypto import get_random_string
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from pretix.base.models.base import LoggedModel
|
||||
@@ -62,6 +63,19 @@ class Organizer(LoggedModel):
|
||||
Django's built-in cache backends, but puts you into an isolated environment for
|
||||
this organizer, so you don't have to prefix your cache keys. In addition, the cache
|
||||
is being cleared every time the organizer changes.
|
||||
|
||||
.. deprecated:: 1.9
|
||||
Use the property ``cache`` instead.
|
||||
"""
|
||||
return self.cache
|
||||
|
||||
@cached_property
|
||||
def cache(self):
|
||||
"""
|
||||
Returns an :py:class:`ObjectRelatedCache` object. This behaves equivalent to
|
||||
Django's built-in cache backends, but puts you into an isolated environment for
|
||||
this organizer, so you don't have to prefix your cache keys. In addition, the cache
|
||||
is being cleared every time the organizer changes.
|
||||
"""
|
||||
from pretix.base.cache import ObjectRelatedCache
|
||||
|
||||
|
||||
@@ -182,3 +182,13 @@ class TaxRule(LoggedModel):
|
||||
|
||||
# Consumer in different EU country / invalid VAT
|
||||
return True
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
super().delete(*args, **kwargs)
|
||||
if self.event:
|
||||
self.event.cache.clear()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super().save(*args, **kwargs)
|
||||
if self.event:
|
||||
self.event.cache.clear()
|
||||
|
||||
@@ -315,11 +315,11 @@ class Voucher(LoggedModel):
|
||||
def save(self, *args, **kwargs):
|
||||
self.code = self.code.upper()
|
||||
super().save(*args, **kwargs)
|
||||
self.event.get_cache().set('vouchers_exist', True)
|
||||
self.event.cache.set('vouchers_exist', True)
|
||||
|
||||
def delete(self, using=None, keep_parents=False):
|
||||
super().delete(using, keep_parents)
|
||||
self.event.get_cache().delete('vouchers_exist')
|
||||
self.event.cache.delete('vouchers_exist')
|
||||
|
||||
def is_in_cart(self) -> bool:
|
||||
"""
|
||||
|
||||
@@ -68,7 +68,9 @@ class OrganizerUpdateForm(OrganizerForm):
|
||||
KnownDomain.objects.create(organizer=instance, domainname=self.cleaned_data['domain'])
|
||||
elif current_domain:
|
||||
current_domain.delete()
|
||||
instance.get_cache().clear()
|
||||
instance.cache.clear()
|
||||
for ev in instance.events.all():
|
||||
ev.cache.clear()
|
||||
|
||||
return instance
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ def eventreverse(obj, name, kwargs=None):
|
||||
|
||||
c = None
|
||||
if not kwargs:
|
||||
c = obj.get_cache()
|
||||
c = obj.cache
|
||||
url = c.get('urlrev_{}'.format(name))
|
||||
if url:
|
||||
return url
|
||||
|
||||
@@ -25,7 +25,7 @@ def control_nav_import(sender, request=None, **kwargs):
|
||||
|
||||
|
||||
def clear_cache(sender, *args, **kwargs):
|
||||
cache = sender.get_cache()
|
||||
cache = sender.cache
|
||||
cache.delete('statistics_obd_data')
|
||||
cache.delete('statistics_obp_data')
|
||||
cache.delete('statistics_rev_data')
|
||||
|
||||
@@ -32,7 +32,7 @@ class IndexView(EventPermissionRequiredMixin, ChartContainingView, TemplateView)
|
||||
except SubEvent.DoesNotExist:
|
||||
pass
|
||||
|
||||
cache = self.request.event.get_cache()
|
||||
cache = self.request.event.cache
|
||||
ckey = str(subevent.pk) if subevent else 'all'
|
||||
|
||||
# Orders by day
|
||||
|
||||
@@ -175,10 +175,10 @@ class EventIndex(EventViewMixin, CartMixin, TemplateView):
|
||||
context['subevent'] = self.subevent
|
||||
context['cart'] = self.get_cart()
|
||||
context['has_addon_choices'] = get_cart(self.request).filter(item__addons__isnull=False).exists()
|
||||
vouchers_exist = self.request.event.get_cache().get('vouchers_exist')
|
||||
vouchers_exist = self.request.event.cache.get('vouchers_exist')
|
||||
if vouchers_exist is None:
|
||||
vouchers_exist = self.request.event.vouchers.exists()
|
||||
self.request.event.get_cache().set('vouchers_exist', vouchers_exist)
|
||||
self.request.event.cache.set('vouchers_exist', vouchers_exist)
|
||||
context['vouchers_exist'] = vouchers_exist
|
||||
context['ev'] = self.subevent or self.request.event
|
||||
if self.subevent:
|
||||
|
||||
Reference in New Issue
Block a user