mirror of
https://github.com/jazzband/django-dbtemplates.git
synced 2026-03-16 22:20:28 +00:00
Moved setttings over to use AppSettings class.
This commit is contained in:
parent
ca032e70cf
commit
a40204def7
9 changed files with 206 additions and 89 deletions
|
|
@ -4,13 +4,13 @@ from django.contrib import admin
|
|||
from django.utils.translation import ungettext, ugettext_lazy as _
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
from dbtemplates import settings
|
||||
from dbtemplates.conf import settings
|
||||
from dbtemplates.models import (Template,
|
||||
remove_cached_template, add_template_to_cache)
|
||||
|
||||
# Check if django-reversion is installed and use reversions' VersionAdmin
|
||||
# as the base admin class if yes
|
||||
if settings.USE_REVERSION:
|
||||
if settings.DBTEMPLATES_USE_REVERSION:
|
||||
from reversion.admin import VersionAdmin as TemplateModelAdmin
|
||||
else:
|
||||
from django.contrib.admin import ModelAdmin as TemplateModelAdmin
|
||||
|
|
@ -23,8 +23,8 @@ class CodeMirrorTextArea(forms.Textarea):
|
|||
"""
|
||||
class Media:
|
||||
css = dict(screen=[
|
||||
posixpath.join(settings.MEDIA_PREFIX, 'css/editor.css')])
|
||||
js = [posixpath.join(settings.MEDIA_PREFIX, 'js/codemirror.js')]
|
||||
posixpath.join(settings.DBTEMPLATES_MEDIA_PREFIX, 'css/editor.css')])
|
||||
js = [posixpath.join(settings.DBTEMPLATES_MEDIA_PREFIX, 'js/codemirror.js')]
|
||||
|
||||
def render(self, name, value, attrs=None):
|
||||
result = []
|
||||
|
|
@ -43,15 +43,15 @@ class CodeMirrorTextArea(forms.Textarea):
|
|||
lineNumbers: true
|
||||
});
|
||||
</script>
|
||||
""" % dict(media_prefix=settings.MEDIA_PREFIX, name=name))
|
||||
""" % dict(media_prefix=settings.DBTEMPLATES_MEDIA_PREFIX, name=name))
|
||||
return mark_safe(u"".join(result))
|
||||
|
||||
if settings.USE_CODEMIRROR:
|
||||
if settings.DBTEMPLATES_USE_CODEMIRROR:
|
||||
TemplateContentTextArea = CodeMirrorTextArea
|
||||
else:
|
||||
TemplateContentTextArea = forms.Textarea
|
||||
|
||||
if settings.AUTO_POPULATE_CONTENT:
|
||||
if settings.DBTEMPLATES_AUTO_POPULATE_CONTENT:
|
||||
content_help_text = _("Leaving this empty causes Django to look for a "
|
||||
"template with the given name and populate this field with its "
|
||||
"content.")
|
||||
|
|
|
|||
42
dbtemplates/conf.py
Normal file
42
dbtemplates/conf.py
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import posixpath
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
from dbtemplates.utils.settings import AppSettings
|
||||
|
||||
|
||||
class DbTemplatesSettings(AppSettings):
|
||||
USE_CODEMIRROR = False
|
||||
USE_REVERSION = False
|
||||
ADD_DEFAULT_SITE = True
|
||||
AUTO_POPULATE_CONTENT = True
|
||||
MEDIA_PREFIX = None
|
||||
CACHE_BACKEND = None
|
||||
|
||||
def configure_media_prefix(self, value):
|
||||
if value is None:
|
||||
base_url = getattr(self, "STATIC_URL", None)
|
||||
if base_url is None:
|
||||
base_url = self.MEDIA_URL
|
||||
value = posixpath.join(base_url, "dbtemplates/")
|
||||
return value
|
||||
|
||||
def configure_cache_backend(self, value):
|
||||
# If we are on Django 1.3 AND using the new CACHES setting..
|
||||
if hasattr(self, "CACHES"):
|
||||
if "dbtemplates" in self.CACHES:
|
||||
return "dbtemplates"
|
||||
else:
|
||||
return "default"
|
||||
if isinstance(value, basestring) and value.startswith("dbtemplates."):
|
||||
raise ImproperlyConfigured("Please upgrade to one of the supported "
|
||||
"backends as defined in the Django docs.")
|
||||
return value
|
||||
|
||||
def configure_use_reversion(self, value):
|
||||
if value and 'reversion' not in self.INSTALLED_APPS:
|
||||
raise ImproperlyConfigured("Please add 'reversion' to your "
|
||||
"INSTALLED_APPS setting to make use of it in dbtemplates.")
|
||||
return value
|
||||
|
||||
settings = DbTemplatesSettings("DBTEMPLATES")
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
import os
|
||||
from optparse import make_option
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.sites.models import Site
|
||||
from django.core.management.base import CommandError, NoArgsCommand
|
||||
from django.template.loaders.app_directories import app_template_dirs
|
||||
|
||||
from dbtemplates.conf import settings
|
||||
from dbtemplates.models import Template
|
||||
|
||||
ALWAYS_ASK, FILES_TO_DATABASE, DATABASE_TO_FILES = ('0', '1', '2')
|
||||
|
|
|
|||
|
|
@ -9,9 +9,10 @@ from django.utils.translation import gettext_lazy as _
|
|||
from django.contrib.sites.models import Site
|
||||
from django.contrib.sites.managers import CurrentSiteManager
|
||||
|
||||
from dbtemplates import settings
|
||||
from dbtemplates.utils import (add_default_site, add_template_to_cache,
|
||||
remove_cached_template, get_template_source)
|
||||
from dbtemplates.conf import settings
|
||||
from dbtemplates.utils.cache import add_template_to_cache, remove_cached_template
|
||||
from dbtemplates.utils.template import get_template_source
|
||||
|
||||
|
||||
|
||||
class Template(models.Model):
|
||||
|
|
@ -22,8 +23,8 @@ class Template(models.Model):
|
|||
name = models.CharField(_('name'), max_length=100,
|
||||
help_text=_("Example: 'flatpages/default.html'"))
|
||||
content = models.TextField(_('content'), blank=True)
|
||||
sites = models.ManyToManyField(Site, verbose_name=_('sites'), blank=True,
|
||||
null=True)
|
||||
sites = models.ManyToManyField(Site, verbose_name=_('sites'),
|
||||
blank=True, null=True)
|
||||
creation_date = models.DateTimeField(_('creation date'),
|
||||
default=datetime.now)
|
||||
last_changed = models.DateTimeField(_('last changed'),
|
||||
|
|
@ -59,11 +60,24 @@ class Template(models.Model):
|
|||
self.last_changed = datetime.now()
|
||||
# If content is empty look for a template with the given name and
|
||||
# populate the template instance with its content.
|
||||
if settings.AUTO_POPULATE_CONTENT and not self.content:
|
||||
if settings.DBTEMPLATES_AUTO_POPULATE_CONTENT and not self.content:
|
||||
self.populate()
|
||||
super(Template, self).save(*args, **kwargs)
|
||||
|
||||
|
||||
def add_default_site(instance, **kwargs):
|
||||
"""
|
||||
Called via Django's signals to cache the templates, if the template
|
||||
in the database was added or changed, only if
|
||||
DBTEMPLATES_ADD_DEFAULT_SITE setting is set.
|
||||
"""
|
||||
if not settings.DBTEMPLATES_ADD_DEFAULT_SITE:
|
||||
return
|
||||
current_site = Site.objects.get_current()
|
||||
if current_site not in instance.sites.all():
|
||||
instance.sites.add(current_site)
|
||||
|
||||
|
||||
signals.post_save.connect(add_default_site, sender=Template)
|
||||
signals.post_save.connect(add_template_to_cache, sender=Template)
|
||||
signals.pre_delete.connect(remove_cached_template, sender=Template)
|
||||
|
|
|
|||
|
|
@ -1,33 +0,0 @@
|
|||
import posixpath
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
if "dbtemplates" in getattr(settings, "CACHES", {}):
|
||||
# If we are on Django 1.3 AND using the new CACHES setting..
|
||||
cache = "dbtemplates"
|
||||
else:
|
||||
# ..or fall back to the old CACHE_BACKEND setting
|
||||
cache = getattr(settings, "DBTEMPLATES_CACHE_BACKEND", None)
|
||||
if isinstance(cache, basestring) and cache.startswith("dbtemplates."):
|
||||
raise ImproperlyConfigured("Please upgrade to one of the supported "
|
||||
"backends as defined in the Django docs.")
|
||||
CACHE_BACKEND = cache
|
||||
|
||||
ADD_DEFAULT_SITE = getattr(settings, 'DBTEMPLATES_ADD_DEFAULT_SITE', True)
|
||||
|
||||
AUTO_POPULATE_CONTENT = getattr(
|
||||
settings, 'DBTEMPLATES_AUTO_POPULATE_CONTENT', True)
|
||||
|
||||
base_url = getattr(settings, "STATIC_URL", None)
|
||||
if base_url is None:
|
||||
base_url = settings.MEDIA_URL
|
||||
MEDIA_PREFIX = getattr(settings, 'DBTEMPLATES_MEDIA_PREFIX',
|
||||
posixpath.join(base_url, "dbtemplates/"))
|
||||
|
||||
USE_REVERSION = getattr(settings, 'DBTEMPLATES_USE_REVERSION', False)
|
||||
|
||||
if USE_REVERSION and 'reversion' not in settings.INSTALLED_APPS:
|
||||
raise ImproperlyConfigured("Please add reversion to your "
|
||||
"INSTALLED_APPS setting to make use of it in dbtemplates.")
|
||||
|
||||
USE_CODEMIRROR = getattr(settings, 'DBTEMPLATES_USE_CODEMIRROR', False)
|
||||
|
|
@ -1,65 +1,49 @@
|
|||
from django import VERSION
|
||||
from __future__ import with_statement
|
||||
|
||||
from django.core.management import call_command
|
||||
from django.template import loader, Context
|
||||
from django.test import TestCase
|
||||
|
||||
from django.contrib.sites.models import Site
|
||||
|
||||
from dbtemplates import settings
|
||||
from dbtemplates.loader import load_template_source
|
||||
from dbtemplates.conf import settings
|
||||
from dbtemplates.models import Template
|
||||
from dbtemplates.utils import get_template_source
|
||||
from dbtemplates.utils.template import get_template_source
|
||||
|
||||
|
||||
class DbTemplatesTestCase(TestCase):
|
||||
def setUp(self):
|
||||
self.site1, created1 = Site.objects.get_or_create(domain="example.com", name="example.com")
|
||||
self.site2, created2 = Site.objects.get_or_create(domain="example.org", name="example.org")
|
||||
self.t1, _ = Template.objects.get_or_create(name='base.html', content='base')
|
||||
self.t2, _ = Template.objects.get_or_create(name='sub.html', content='sub')
|
||||
self.t2.sites.add(self.site2)
|
||||
|
||||
def test_basiscs(self):
|
||||
t1 = Template(name='base.html', content='<html><head></head><body>{% block content %}Welcome at {{ title }}{% endblock %}</body></html>')
|
||||
t1.save()
|
||||
self.assertEqual(Site.objects.get_current(), t1.sites.all()[0])
|
||||
self.assertTrue("Welcome at" in t1.content)
|
||||
self.assertEqual(list(self.t1.sites.all()), [self.site1])
|
||||
self.assertTrue("base" in self.t1.content)
|
||||
self.assertEqual(list(Template.objects.filter(sites=self.site1)), [self.t1, self.t2])
|
||||
self.assertEqual(list(self.t2.sites.all()), [self.site1, self.site2])
|
||||
|
||||
t2 = Template(name='sub.html', content='{% extends "base.html" %}{% block content %}This is {{ title }}{% endblock %}')
|
||||
t2.save()
|
||||
t2.sites.add(self.site2)
|
||||
|
||||
self.assertEqual(list(Template.objects.filter(sites=self.site1)), [t1, t2])
|
||||
self.assertEqual(list(t2.sites.all()), [self.site1, self.site2])
|
||||
def test_empty_sites(self):
|
||||
old_add_default_site = settings.DBTEMPLATES_ADD_DEFAULT_SITE
|
||||
try:
|
||||
settings.DBTEMPLATES_ADD_DEFAULT_SITE = False
|
||||
self.t3 = Template.objects.create(name='footer.html', content='footer')
|
||||
self.assertEqual(list(self.t3.sites.all()), [])
|
||||
finally:
|
||||
settings.DBTEMPLATES_ADD_DEFAULT_SITE = old_add_default_site
|
||||
|
||||
def test_load_templates(self):
|
||||
self.test_basiscs()
|
||||
original_template_source_loaders = loader.template_source_loaders
|
||||
loader.template_source_loaders = [load_template_source]
|
||||
try:
|
||||
result1 = loader.get_template("base.html").render(Context({'title':'MainPage'}))
|
||||
self.assertEqual(result1, u'<html><head></head><body>Welcome at MainPage</body></html>')
|
||||
result2 = loader.get_template("sub.html").render(Context({'title':'SubPage'}))
|
||||
self.assertEqual(result2, u'<html><head></head><body>This is SubPage</body></html>')
|
||||
|
||||
if VERSION[:2] >= (1, 2):
|
||||
from dbtemplates.loader import Loader
|
||||
dbloader = Loader()
|
||||
loader.template_source_loaders = [dbloader.load_template_source]
|
||||
result = loader.get_template("base.html").render(Context({'title':'MainPage'}))
|
||||
self.assertEqual(result, u'<html><head></head><body>Welcome at MainPage</body></html>')
|
||||
result2 = loader.get_template("sub.html").render(Context({'title':'SubPage'}))
|
||||
self.assertEqual(result2, u'<html><head></head><body>This is SubPage</body></html>')
|
||||
finally:
|
||||
loader.template_source_loaders = original_template_source_loaders
|
||||
result = loader.get_template("base.html").render(Context({}))
|
||||
self.assertEqual(result, 'base')
|
||||
result2 = loader.get_template("sub.html").render(Context({}))
|
||||
self.assertEqual(result2, 'sub')
|
||||
|
||||
def test_error_templates_creation(self):
|
||||
call_command('create_error_templates', force=True, verbosity=0)
|
||||
self.assertEqual(list(Template.objects.filter(sites=self.site1)),
|
||||
list(Template.objects.filter()))
|
||||
|
||||
def test_disabling_default_site(self):
|
||||
old_add_default_site = settings.ADD_DEFAULT_SITE
|
||||
settings.ADD_DEFAULT_SITE = False
|
||||
t3 = Template.objects.create(name='footer.html', content='ohai')
|
||||
self.assertEqual(list(t3.sites.all()), [])
|
||||
settings.ADD_DEFAULT_SITE = old_add_default_site
|
||||
list(Template.objects.filter()))
|
||||
|
||||
def test_automatic_sync(self):
|
||||
admin_base_template = get_template_source('admin/base.html')
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ def get_cache_key(name):
|
|||
return 'dbtemplates::%s::%s' % (name, current_site.pk)
|
||||
|
||||
|
||||
def set_and_return(content):
|
||||
def set_and_return(content, display_name):
|
||||
# Save in cache backend explicitly if manually deleted or invalidated
|
||||
if cache:
|
||||
cache.set(cache_key, content)
|
||||
|
|
|
|||
105
dbtemplates/utils/settings.py
Normal file
105
dbtemplates/utils/settings.py
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
from inspect import getmembers
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class AppSettings(object):
|
||||
"""
|
||||
An app setting object to be used for handling app setting defaults
|
||||
gracefully and providing a nice API for them. Say you have an app
|
||||
called ``myapp`` and want to define a few defaults, and refer to the
|
||||
defaults easily in the apps code. Add a ``settings.py`` to your app::
|
||||
|
||||
from path.to.utils import AppSettings
|
||||
|
||||
class MyAppSettings(AppSettings):
|
||||
SETTING_1 = "one"
|
||||
SETTING_2 = (
|
||||
"two",
|
||||
)
|
||||
|
||||
Then initialize the setting with the correct prefix in the location of
|
||||
of your choice, e.g. ``conf.py`` of the app module::
|
||||
|
||||
settings = MyAppSettings(prefix="MYAPP")
|
||||
|
||||
The ``MyAppSettings`` instance will automatically look at Django's
|
||||
global setting to determine each of the settings and respect the
|
||||
provided ``prefix``. E.g. adding this to your site's ``settings.py``
|
||||
will set the ``SETTING_1`` setting accordingly::
|
||||
|
||||
MYAPP_SETTING_1 = "uno"
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Instead of using ``from django.conf import settings`` as you would
|
||||
usually do, you can switch to using your apps own settings module
|
||||
to access the app settings::
|
||||
|
||||
from myapp.conf import settings
|
||||
|
||||
print myapp_settings.MYAPP_SETTING_1
|
||||
|
||||
``AppSettings`` instances also work as pass-throughs for other
|
||||
global settings that aren't related to the app. For example the
|
||||
following code is perfectly valid::
|
||||
|
||||
from myapp.conf import settings
|
||||
|
||||
if "myapp" in settings.INSTALLED_APPS:
|
||||
print "yay, myapp is installed!"
|
||||
|
||||
Custom handling
|
||||
---------------
|
||||
|
||||
Each of the settings can be individually configured with callbacks.
|
||||
For example, in case a value of a setting depends on other settings
|
||||
or other dependencies. The following example sets one setting to a
|
||||
different value depending on a global setting::
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
class MyCustomAppSettings(AppSettings):
|
||||
ENABLED = True
|
||||
|
||||
def configure_enabled(self, value):
|
||||
return value and not self.DEBUG
|
||||
|
||||
custom_settings = MyCustomAppSettings("MYAPP")
|
||||
|
||||
The value of ``custom_settings.MYAPP_ENABLED`` will vary depending on the
|
||||
value of the global ``DEBUG`` setting.
|
||||
|
||||
Each of the app settings can be customized by providing
|
||||
a method ``configure_<lower_setting_name>`` that takes the default
|
||||
value as defined in the class attributes as the only parameter.
|
||||
The method needs to return the value to be use for the setting in
|
||||
question.
|
||||
"""
|
||||
def __dir__(self):
|
||||
return sorted(list(set(self.__dict__.keys() + dir(settings))))
|
||||
|
||||
__members__ = lambda self: self.__dir__()
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name.startswith(self._prefix):
|
||||
raise AttributeError("%r object has no attribute %r" %
|
||||
(self.__class__.__name__, name))
|
||||
return getattr(settings, name)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
super(AppSettings, self).__setattr__(name, value)
|
||||
if name in dir(settings):
|
||||
setattr(settings, name, value)
|
||||
|
||||
def __init__(self, prefix):
|
||||
super(AppSettings, self).__setattr__('_prefix', prefix)
|
||||
for setting, class_value in getmembers(self.__class__):
|
||||
if setting == setting.upper():
|
||||
prefixed = "%s_%s" % (prefix.upper(), setting.upper())
|
||||
configured_value = getattr(settings, prefixed, class_value)
|
||||
callback = getattr(self, "configure_%s" % setting.lower(), None)
|
||||
if callable(callback):
|
||||
configured_value = callback(configured_value)
|
||||
delattr(self.__class__, setting)
|
||||
setattr(self, prefixed, configured_value)
|
||||
|
|
@ -15,6 +15,11 @@ if not settings.configured:
|
|||
'django.contrib.admin',
|
||||
'dbtemplates',
|
||||
],
|
||||
TEMPLATE_LOADERS = (
|
||||
'django.template.loaders.filesystem.load_template_source',
|
||||
'django.template.loaders.app_directories.load_template_source',
|
||||
'dbtemplates.loader.Loader',
|
||||
)
|
||||
)
|
||||
|
||||
from django.test.simple import run_tests
|
||||
|
|
|
|||
Loading…
Reference in a new issue