Restructure settings framework

This commit is contained in:
Raphael Michel
2015-03-06 00:16:46 +01:00
parent 386bd032cf
commit 6ffdd33cf5
4 changed files with 146 additions and 99 deletions

View File

@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0013_merge'),
]
operations = [
migrations.RenameField(
model_name='eventsetting',
old_name='event',
new_name='object',
),
migrations.RenameField(
model_name='organizersetting',
old_name='organizer',
new_name='object',
),
]

View File

@@ -12,6 +12,7 @@ from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from django.template.defaultfilters import date as _date
from django.core.validators import RegexValidator
from pretix.base.settings import SettingsProxy
import six
from versions.models import Versionable as BaseVersionable
from versions.models import VersionedForeignKey, VersionedManyToManyField, get_utc_now
@@ -246,57 +247,12 @@ class Organizer(Versionable):
def __str__(self):
return self.name
class OrganizerSettingsProxy:
"""
This objects allows convenient access to settings stored in the
OrganizerSettings database model. It exposes all settings as properties
and it will do all the nasty defaults stuff for
you. It will return None for non-existing properties.
"""
def __init__(self, organizer):
self._organizer = organizer
self._cached_obj = None
def _cache(self):
if self._cached_obj is None:
self._cached_obj = {}
for setting in self._organizer.setting_objects.current.all():
self._cached_obj[setting.key] = setting
return self._cached_obj
def __getattr__(self, key):
if key in self._cache():
return self._cache()[key].value
if key in OrganizerSetting.DEFAULTS:
return OrganizerSetting.DEFAULTS[key]
return None
def __delattr__(self, key):
if key.startswith('_'):
return super().__delattr__(key)
if key in self._cache():
self._cache()[key].delete()
del self._cache()[key]
def __setattr__(self, key, value):
if key.startswith('_'):
return super().__setattr__(key, value)
if key in self._cache():
s = self._cache()[key]
s = s.clone()
else:
s = OrganizerSetting(organizer=self._organizer, key=key)
s.value = value
s.save()
self._cache()[key] = s
@cached_property
def settings(self):
"""
Returns an object representing this organizer's settings
"""
return Organizer.OrganizerSettingsProxy(self)
return SettingsProxy(self, type=OrganizerSetting)
class OrganizerPermission(Versionable):
@@ -453,55 +409,12 @@ class Event(Versionable):
from pretix.base.cache import EventRelatedCache
return EventRelatedCache(self)
class EventSettingsProxy:
"""
This objects allows convenient access to settings stored in the
EventSettings database model. It exposes all settings as properties
and it will do all the nasty inheritance and defaults stuff for
you. It will return None for non-existing properties.
"""
def __init__(self, event):
self._event = event
self._cached_obj = None
def _cache(self):
if self._cached_obj is None:
self._cached_obj = {}
for setting in self._event.setting_objects.current.all():
self._cached_obj[setting.key] = setting
return self._cached_obj
def __getattr__(self, key):
if key in self._cache():
return self._cache()[key].value
return getattr(self._event.organizer.settings, key)
def __setattr__(self, key, value):
if key.startswith('_'):
return super().__setattr__(key, value)
if key in self._cache():
s = self._cache()[key]
s = s.clone()
else:
s = EventSetting(event=self._event, key=key)
s.value = value
s.save()
self._cache()[key] = s
def __delattr__(self, key):
if key.startswith('_'):
return super().__delattr__(key)
if key in self._cache():
self._cache()[key].delete()
del self._cache()[key]
@cached_property
def settings(self):
"""
Returns an object representing this event's settings
"""
return Event.EventSettingsProxy(self)
return SettingsProxy(self, type=EventSetting, parent=self.organizer)
class EventPermission(Versionable):
@@ -1468,7 +1381,7 @@ class EventSetting(Versionable):
An event settings is a key-value setting which can be set for a
specific event
"""
event = VersionedForeignKey(Event, related_name='setting_objects')
object = VersionedForeignKey(Event, related_name='setting_objects')
key = models.CharField(max_length=255)
value = models.TextField()
@@ -1478,12 +1391,6 @@ class OrganizerSetting(Versionable):
An event option is a key-value setting which can be set for an
organizer. It will be inherited by the events of this organizer
"""
DEFAULTS = {
'user_mail_required': 'False',
'max_items_per_order': '10',
'attendee_names_asked': 'True',
'attendee_names_required': 'False',
}
organizer = VersionedForeignKey(Organizer, related_name='setting_objects')
object = VersionedForeignKey(Organizer, related_name='setting_objects')
key = models.CharField(max_length=255)
value = models.TextField()

115
src/pretix/base/settings.py Normal file
View File

@@ -0,0 +1,115 @@
DEFAULTS = {
'user_mail_required': 'False',
'max_items_per_order': '10',
'attendee_names_asked': 'True',
'attendee_names_required': 'False',
}
class SettingsProxy:
"""
This objects allows convenient access to settings stored in the
EventSettings/OrganizerSettings database model. It exposes all settings as
properties and it will do all the nasty inheritance and defaults stuff for
you. It will return None for non-existing properties.
"""
def __init__(self, obj, parent=None, type=None):
self._obj = obj
self._parent = parent
self._cached_obj = None
self._type = type
def _cache(self):
if self._cached_obj is None:
self._cached_obj = {}
for setting in self._obj.setting_objects.current.all():
self._cached_obj[setting.key] = setting
return self._cached_obj
def get(self, key, default=None):
if key in self._cache():
return self._cache()[key].value
value = None
if self._parent:
value = self._parent.settings.get(key)
if value is None and key in DEFAULTS:
return DEFAULTS[key]
if value is None and default is not None:
return default
return value
def __getitem__(self, key):
return self.get(key)
def __getattr__(self, key):
return self.get(key)
def __setattr__(self, key, value):
if key.startswith('_'):
return super().__setattr__(key, value)
self.set(key, value)
def __setitem__(self, key, value):
self.set(key, value)
def set(self, key, value):
if key in self._cache():
s = self._cache()[key]
s = s.clone()
else:
s = self._type(object=self._obj, key=key)
s.value = value
s.save()
self._cache()[key] = s
def __delattr__(self, key):
if key.startswith('_'):
return super().__delattr__(key)
return self.__delitem__(key)
def __delitem__(self, key):
if key in self._cache():
self._cache()[key].delete()
del self._cache()[key]
class SettingsSandbox:
"""
Transparently proxied access to event settings, handling your domain-
prefixes for you.
"""
def __init__(self, type, key, event):
self._event = event
self._type = type
self._key = key
def _convert_key(self, key):
return '%s_%s_%s' % (self._type, self._key, key)
def __setitem__(self, key, value):
self.set(key, value)
def __setattr__(self, key, value):
if key.startswith('_'):
return super().__setattr__(key, value)
self.set(key, value)
def __getattr__(self, item):
return self.get(item)
def __getitem__(self, item):
return self.get(item)
def __delitem__(self, key):
del self._event.settings[self._convert_key(key)]
def __delattr__(self, key):
del self._event.settings[self._convert_key(key)]
def get(self, key, default=None):
return self._event.settings.get(self._convert_key(key), default)
def set(self, key, value):
self._event.settings.set(self._convert_key(key), value)

View File

@@ -8,6 +8,7 @@ from pretix.base.models import (
Order, OrderPosition, CartPosition,
OrganizerSetting)
from pretix.base.types import VariationDict
from pretix.base import settings
class ItemVariationsTest(TestCase):
@@ -297,7 +298,7 @@ class QuotaTestCase(TestCase):
class SettingsTestCase(TestCase):
def setUp(self):
OrganizerSetting.DEFAULTS['test_default'] = 'def'
settings.DEFAULTS['test_default'] = 'def'
self.organizer = Organizer.objects.create(name='Dummy', slug='dummy')
self.event = Event.objects.create(
organizer=self.organizer, name='Dummy', slug='dummy',