mirror of
https://github.com/jazzband/django-dbtemplates.git
synced 2026-05-04 21:54:52 +00:00
Merge branch 'release/1.1'
This commit is contained in:
commit
f01a530200
32 changed files with 553 additions and 272 deletions
|
|
@ -1,4 +1,4 @@
|
|||
[django-dbtemplates.django]
|
||||
[django-dbtemplates.main]
|
||||
file_filter = dbtemplates/locale/<lang>/LC_MESSAGES/django.po
|
||||
source_file = dbtemplates/locale/en/LC_MESSAGES/django.po
|
||||
source_lang = en
|
||||
|
|
|
|||
2
LICENSE
2
LICENSE
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2007-2010, Jannis Leidel and contributors
|
||||
Copyright (c) 2007-2011, Jannis Leidel and contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
VERSION = (1, 0, 1, "f", 0) # following PEP 386
|
||||
VERSION = (1, 1, 0, "f", 0) # following PEP 386
|
||||
DEV_N = None
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -22,9 +22,9 @@ class CodeMirrorTextArea(forms.Textarea):
|
|||
content field of the Template model.
|
||||
"""
|
||||
class Media:
|
||||
css = dict(screen=[
|
||||
posixpath.join(settings.MEDIA_PREFIX, 'css/editor.css')])
|
||||
js = [posixpath.join(settings.MEDIA_PREFIX, 'js/codemirror.js')]
|
||||
css = dict(screen=[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.")
|
||||
|
|
@ -86,8 +86,10 @@ class TemplateAdmin(TemplateModelAdmin):
|
|||
'classes': ('collapse',),
|
||||
}),
|
||||
)
|
||||
filter_horizontal = ('sites',)
|
||||
list_display = ('name', 'creation_date', 'last_changed', 'site_list')
|
||||
list_filter = ('sites',)
|
||||
save_as = True
|
||||
search_fields = ('name', 'content')
|
||||
actions = ['invalidate_cache', 'repopulate_cache']
|
||||
|
||||
|
|
|
|||
43
dbtemplates/conf.py
Normal file
43
dbtemplates/conf.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
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,14 +1,13 @@
|
|||
import warnings
|
||||
from django import VERSION
|
||||
from django.conf import settings
|
||||
from django.contrib.sites.models import Site
|
||||
from django.template import TemplateDoesNotExist
|
||||
|
||||
from dbtemplates.conf import settings
|
||||
from dbtemplates.models import Template
|
||||
from dbtemplates.utils import cache, get_cache_key
|
||||
from dbtemplates.utils.cache import cache, get_cache_key, set_and_return
|
||||
from django.template.loader import BaseLoader
|
||||
|
||||
|
||||
def load_template_source(template_name, template_dirs=None, annoy=True):
|
||||
class Loader(BaseLoader):
|
||||
"""
|
||||
A custom template loader to load templates from the database.
|
||||
|
||||
|
|
@ -17,43 +16,29 @@ def load_template_source(template_name, template_dirs=None, annoy=True):
|
|||
it falls back to query the database field ``name`` with the template path
|
||||
and ``sites`` with the current site.
|
||||
"""
|
||||
if VERSION[:2] >= (1, 2) and annoy:
|
||||
# For backward compatibility
|
||||
warnings.warn(
|
||||
"`dbtemplates.loader.load_template_source` is deprecated; "
|
||||
"use `dbtemplates.loader.Loader` instead.", DeprecationWarning)
|
||||
site = Site.objects.get_current()
|
||||
display_name = 'db:%s:%s:%s' % (settings.DATABASE_ENGINE,
|
||||
template_name, site.domain)
|
||||
cache_key = get_cache_key(template_name)
|
||||
if cache:
|
||||
try:
|
||||
backend_template = cache.get(cache_key)
|
||||
if backend_template:
|
||||
return backend_template, template_name
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
template = Template.on_site.get(name__exact=template_name)
|
||||
# Save in cache backend explicitly if manually deleted or invalidated
|
||||
is_usable = True
|
||||
|
||||
def load_template_source(self, template_name, template_dirs=None):
|
||||
site = Site.objects.get_current()
|
||||
display_name = 'dbtemplates:%s:%s:%s' % (settings.DATABASE_ENGINE,
|
||||
template_name, site.domain)
|
||||
cache_key = get_cache_key(template_name)
|
||||
if cache:
|
||||
cache.set(cache_key, template.content)
|
||||
return (template.content, display_name)
|
||||
except:
|
||||
pass
|
||||
raise TemplateDoesNotExist(template_name)
|
||||
load_template_source.is_usable = True
|
||||
|
||||
|
||||
if VERSION[:2] >= (1, 2):
|
||||
# providing a class based loader for Django >= 1.2, yay!
|
||||
from django.template.loader import BaseLoader
|
||||
|
||||
class Loader(BaseLoader):
|
||||
__doc__ = load_template_source.__doc__
|
||||
|
||||
is_usable = True
|
||||
|
||||
def load_template_source(self, template_name, template_dirs=None):
|
||||
return load_template_source(
|
||||
template_name, template_dirs, annoy=False)
|
||||
try:
|
||||
backend_template = cache.get(cache_key)
|
||||
if backend_template:
|
||||
return backend_template, template_name
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
template = Template.objects.get(name__exact=template_name)
|
||||
return set_and_return(cache_key, template.content, display_name)
|
||||
except (Template.MultipleObjectsReturned, Template.DoesNotExist):
|
||||
try:
|
||||
template = Template.objects.get(
|
||||
name__exact=template_name, sites__in=[site.id])
|
||||
return set_and_return(
|
||||
cache_key, template.content, display_name)
|
||||
except Template.DoesNotExist:
|
||||
pass
|
||||
raise TemplateDoesNotExist(template_name)
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2010-11-07 00:02+0100\n"
|
||||
"POT-Creation-Date: 2011-07-06 21:19+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
|
@ -16,28 +16,28 @@ msgstr ""
|
|||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: admin.py:53
|
||||
#: admin.py:55
|
||||
msgid ""
|
||||
"Leaving this empty causes Django to look for a template with the given name "
|
||||
"and populate this field with its content."
|
||||
msgstr ""
|
||||
|
||||
#: admin.py:77
|
||||
#: admin.py:81
|
||||
msgid "Advanced"
|
||||
msgstr ""
|
||||
|
||||
#: admin.py:80
|
||||
#: admin.py:84
|
||||
msgid "Date/time"
|
||||
msgstr ""
|
||||
|
||||
#: admin.py:98
|
||||
#: admin.py:100
|
||||
#, python-format
|
||||
msgid "Cache of one template successfully invalidated."
|
||||
msgid_plural "Cache of %(count)d templates successfully invalidated."
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: admin.py:102
|
||||
#: admin.py:104
|
||||
msgid "Invalidate cache of selected templates"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -52,34 +52,34 @@ msgstr[1] ""
|
|||
msgid "Repopulate cache with selected templates"
|
||||
msgstr ""
|
||||
|
||||
#: admin.py:119 models.py:29
|
||||
#: admin.py:120 models.py:25
|
||||
msgid "sites"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:26
|
||||
#: models.py:22
|
||||
msgid "name"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:27
|
||||
#: models.py:23
|
||||
msgid "Example: 'flatpages/default.html'"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:28
|
||||
#: models.py:24
|
||||
msgid "content"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:30
|
||||
#: models.py:27
|
||||
msgid "creation date"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:32
|
||||
#: models.py:29
|
||||
msgid "last changed"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:40
|
||||
#: models.py:37
|
||||
msgid "template"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:41
|
||||
#: models.py:38
|
||||
msgid "templates"
|
||||
msgstr ""
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,15 +1,15 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#
|
||||
# Ville Säävuori <ville@syneus.fi>, 2011.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: django-dbtemplates\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"Last-Translator: Jaakko Holster <holster@iki.fi>\n"
|
||||
"POT-Creation-Date: 2011-01-31 11:10+0100\n"
|
||||
"PO-Revision-Date: 2011-01-31 10:08+0000\n"
|
||||
"Report-Msgid-Bugs-To: https://github.com/jezdez/django-dbtemplates/issues\n"
|
||||
"POT-Creation-Date: 2010-11-07 00:02+0100\n"
|
||||
"PO-Revision-Date: 2011-06-19 11:22+0000\n"
|
||||
"Last-Translator: Uninen <ville@syneus.fi>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
|
@ -22,8 +22,8 @@ msgid ""
|
|||
"Leaving this empty causes Django to look for a template with the given name "
|
||||
"and populate this field with its content."
|
||||
msgstr ""
|
||||
"Mikäli kenttä on tyhjä, Django etsii samannimistä sivupohjaa ja täyttää "
|
||||
"kentän sen sisällöllä."
|
||||
"Jos tämä jätetään tyhjäksi, Django etsiin annetulla nimellä olevan "
|
||||
"mallipohjan ja täyttää tähän kenttään sen sisällön."
|
||||
|
||||
#: admin.py:77
|
||||
msgid "Advanced"
|
||||
|
|
@ -37,25 +37,25 @@ msgstr "Päiväys/aika"
|
|||
#, python-format
|
||||
msgid "Cache of one template successfully invalidated."
|
||||
msgid_plural "Cache of %(count)d templates successfully invalidated."
|
||||
msgstr[0] "Sivupohja poistettu välimuistista."
|
||||
msgstr[1] "%(count)d sivupohjaa poistettu välimuistista."
|
||||
msgstr[0] "Yhden mallipohjan välimuisti on onnistuneesti tyhjennetty."
|
||||
msgstr[1] "%(count)d mallipohjan välimusti on onnistuneesti tyhjennetty."
|
||||
|
||||
#: admin.py:102
|
||||
msgid "Invalidate cache of selected templates"
|
||||
msgstr "Poista valitut sivupohjat välimuistista."
|
||||
msgstr "Tyhjennä valittujen mallipohjien välimuisti."
|
||||
|
||||
#: admin.py:111
|
||||
#, python-format
|
||||
msgid "Cache successfully repopulated with one template."
|
||||
msgid_plural "Cache successfully repopulated with %(count)d templates."
|
||||
msgstr[0] "Sivupohja lisätty välimuistiin."
|
||||
msgstr[1] "%(count)d sivupohjaa lisätty välimuistiin."
|
||||
msgstr[0] "Yhden mallipohjan välimuisti on täytetty onnistuneesti."
|
||||
msgstr[1] "%(count)d mallipohjan välimuisti on täytetty onnistuneesti."
|
||||
|
||||
#: admin.py:115
|
||||
msgid "Repopulate cache with selected templates"
|
||||
msgstr "Lisää valitut sivupohjat välimuistiin."
|
||||
msgstr "Täytä valittujen mallipohjien välimuisti."
|
||||
|
||||
#: admin.py:119
|
||||
#: admin.py:119 models.py:29
|
||||
msgid "sites"
|
||||
msgstr "sivustot"
|
||||
|
||||
|
|
@ -65,24 +65,26 @@ msgstr "nimi"
|
|||
|
||||
#: models.py:27
|
||||
msgid "Example: 'flatpages/default.html'"
|
||||
msgstr "Esimerkki: 'flatpages/default.html'"
|
||||
msgstr "Esimerkiksi: 'flatpages/default.html'"
|
||||
|
||||
#: models.py:28
|
||||
msgid "content"
|
||||
msgstr "sisältö"
|
||||
msgstr "sisätö"
|
||||
|
||||
#: models.py:30
|
||||
msgid "creation date"
|
||||
msgstr "luotu"
|
||||
msgstr "luontipäivä"
|
||||
|
||||
#: models.py:32
|
||||
msgid "last changed"
|
||||
msgstr "muokattu"
|
||||
msgstr "viimeksi muutettu"
|
||||
|
||||
#: models.py:40
|
||||
msgid "template"
|
||||
msgstr "sivupohja"
|
||||
msgstr "mallipohja"
|
||||
|
||||
#: models.py:41
|
||||
msgid "templates"
|
||||
msgstr "sivupohjat"
|
||||
msgstr "mallipohjat"
|
||||
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,16 +1,16 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#
|
||||
# Herson Hersonls <hersonls@gmail.com>, 2011.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: django-dbtemplates\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"Last-Translator: Diego Búrigo Zacarão <diegobz@fedoraproject.org>\n"
|
||||
"Language-Team: Brazilian Portuguese <fedora-trans-pt_br@redhat.com>\n"
|
||||
"POT-Creation-Date: 2011-01-31 11:10+0100\n"
|
||||
"PO-Revision-Date: 2011-01-31 10:08+0000\n"
|
||||
"Report-Msgid-Bugs-To: https://github.com/jezdez/django-dbtemplates/issues\n"
|
||||
"POT-Creation-Date: 2010-11-07 00:02+0100\n"
|
||||
"PO-Revision-Date: 2011-06-01 18:11+0000\n"
|
||||
"Last-Translator: hersonls <hersonls@gmail.com>\n"
|
||||
"Language-Team: Portuguese (Brazilian) (http://www.transifex.net/projects/p/django-dbtemplates/team/pt_BR/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
|
@ -27,7 +27,7 @@ msgstr ""
|
|||
|
||||
#: admin.py:77
|
||||
msgid "Advanced"
|
||||
msgstr ""
|
||||
msgstr "Avançado"
|
||||
|
||||
#: admin.py:80
|
||||
msgid "Date/time"
|
||||
|
|
@ -86,3 +86,5 @@ msgstr "modelo"
|
|||
#: models.py:41
|
||||
msgid "templates"
|
||||
msgstr "modelos"
|
||||
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -32,7 +32,7 @@ msgid "Date/time"
|
|||
msgstr "日期/时间"
|
||||
|
||||
#: admin.py:98
|
||||
#, python-format
|
||||
#, fuzzy, python-format
|
||||
msgid "Cache of one template successfully invalidated."
|
||||
msgid_plural "Cache of %(count)d templates successfully invalidated."
|
||||
msgstr[0] "该模板的缓存已经成功撤销。"
|
||||
|
|
@ -42,7 +42,7 @@ msgid "Invalidate cache of selected templates"
|
|||
msgstr "撤销选中模板的缓存"
|
||||
|
||||
#: admin.py:111
|
||||
#, python-format
|
||||
#, fuzzy, python-format
|
||||
msgid "Cache successfully repopulated with one template."
|
||||
msgid_plural "Cache successfully repopulated with %(count)d templates."
|
||||
msgstr[0] "该模板的缓存已经成功启用。"
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import os
|
||||
import codecs
|
||||
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')
|
||||
|
|
@ -24,13 +25,16 @@ class Command(NoArgsCommand):
|
|||
"files from database templates"),
|
||||
make_option("-a", "--app-first", action="store_true", dest="app_first",
|
||||
default=False, help="look for templates in applications "
|
||||
"directories before project templates"))
|
||||
"directories before project templates"),
|
||||
make_option("-d", "--delete", action="store_true", dest="delete",
|
||||
default=False, help="Delete templates after syncing"))
|
||||
|
||||
def handle_noargs(self, **options):
|
||||
extension = options.get('ext')
|
||||
force = options.get('force')
|
||||
overwrite = options.get('overwrite')
|
||||
app_first = options.get('app_first')
|
||||
delete = options.get('delete')
|
||||
|
||||
if not extension.startswith("."):
|
||||
extension = ".%s" % extension
|
||||
|
|
@ -53,10 +57,12 @@ class Command(NoArgsCommand):
|
|||
|
||||
for templatedir in templatedirs:
|
||||
for dirpath, subdirs, filenames in os.walk(templatedir):
|
||||
for f in [f for f in filenames if f.endswith(extension)
|
||||
and not f.startswith(".")]:
|
||||
for f in [f for f in filenames
|
||||
if f.endswith(extension) and not f.startswith(".")]:
|
||||
path = os.path.join(dirpath, f)
|
||||
name = path.split(templatedir)[1][1:]
|
||||
name = path.split(templatedir)[1]
|
||||
if name.startswith('/'):
|
||||
name = name[1:]
|
||||
try:
|
||||
t = Template.on_site.get(name__exact=name)
|
||||
except Template.DoesNotExist:
|
||||
|
|
@ -67,7 +73,7 @@ class Command(NoArgsCommand):
|
|||
" (y/[n]): """ % (name, path))
|
||||
if force or confirm.lower().startswith('y'):
|
||||
t = Template(name=name,
|
||||
content=open(path, "r").read())
|
||||
content=codecs.open(path, "r").read())
|
||||
t.save()
|
||||
t.sites.add(site)
|
||||
else:
|
||||
|
|
@ -83,16 +89,23 @@ class Command(NoArgsCommand):
|
|||
path, t.__repr__()))
|
||||
else:
|
||||
confirm = overwrite
|
||||
if confirm == '' or confirm in (
|
||||
FILES_TO_DATABASE, DATABASE_TO_FILES):
|
||||
if confirm in ('', FILES_TO_DATABASE, DATABASE_TO_FILES):
|
||||
if confirm == FILES_TO_DATABASE:
|
||||
t.content = open(path, 'r').read()
|
||||
t.content = codecs.open(path, 'r').read()
|
||||
t.save()
|
||||
t.sites.add(site)
|
||||
if delete:
|
||||
try:
|
||||
os.remove(path)
|
||||
except OSError:
|
||||
raise CommandError(
|
||||
u"Couldn't delete %s" % path)
|
||||
elif confirm == DATABASE_TO_FILES:
|
||||
try:
|
||||
f = open(path, 'w')
|
||||
f = codecs.open(path, 'w')
|
||||
f.write(t.content)
|
||||
finally:
|
||||
f.close()
|
||||
if delete:
|
||||
t.delete()
|
||||
break
|
||||
|
|
|
|||
57
dbtemplates/migrations/0001_initial.py
Normal file
57
dbtemplates/migrations/0001_initial.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# encoding: utf-8
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
|
||||
# Adding model 'Template'
|
||||
db.create_table('django_template', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=100)),
|
||||
('content', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
('creation_date', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
|
||||
('last_changed', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
|
||||
))
|
||||
db.send_create_signal('dbtemplates', ['Template'])
|
||||
|
||||
# Adding M2M table for field sites on 'Template'
|
||||
db.create_table('django_template_sites', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('template', models.ForeignKey(orm['dbtemplates.template'], null=False)),
|
||||
('site', models.ForeignKey(orm['sites.site'], null=False))
|
||||
))
|
||||
db.create_unique('django_template_sites', ['template_id', 'site_id'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Deleting model 'Template'
|
||||
db.delete_table('django_template')
|
||||
|
||||
# Removing M2M table for field sites on 'Template'
|
||||
db.delete_table('django_template_sites')
|
||||
|
||||
|
||||
models = {
|
||||
'dbtemplates.template': {
|
||||
'Meta': {'ordering': "('name',)", 'object_name': 'Template', 'db_table': "'django_template'"},
|
||||
'content': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_changed': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
|
||||
'sites': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['sites.Site']", 'symmetrical': 'False'})
|
||||
},
|
||||
'sites.site': {
|
||||
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
|
||||
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['dbtemplates']
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
# encoding: utf-8
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
|
||||
# Removing unique constraint on 'Template', fields ['name']
|
||||
db.delete_unique('django_template', ['name'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Adding unique constraint on 'Template', fields ['name']
|
||||
db.create_unique('django_template', ['name'])
|
||||
|
||||
|
||||
models = {
|
||||
'dbtemplates.template': {
|
||||
'Meta': {'ordering': "('name',)", 'object_name': 'Template', 'db_table': "'django_template'"},
|
||||
'content': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_changed': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'sites': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['sites.Site']", 'symmetrical': 'False'})
|
||||
},
|
||||
'sites.site': {
|
||||
'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"},
|
||||
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['dbtemplates']
|
||||
0
dbtemplates/migrations/__init__.py
Normal file
0
dbtemplates/migrations/__init__.py
Normal file
|
|
@ -9,9 +9,9 @@ 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):
|
||||
|
|
@ -19,10 +19,11 @@ class Template(models.Model):
|
|||
Defines a template model for use with the database template loader.
|
||||
The field ``name`` is the equivalent to the filename of a static template.
|
||||
"""
|
||||
name = models.CharField(_('name'), unique=True, max_length=100,
|
||||
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'))
|
||||
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'),
|
||||
|
|
@ -58,11 +59,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,36 +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 not cache:
|
||||
raise ImproperlyConfigured("Please specify a dbtemplates "
|
||||
"cache backend in your settings.")
|
||||
elif 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,66 +1,93 @@
|
|||
from django import VERSION
|
||||
from __future__ import with_statement
|
||||
import codecs
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
|
||||
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.models import Template, get_template_source
|
||||
from dbtemplates.conf import settings
|
||||
from dbtemplates.models import Template
|
||||
from dbtemplates.utils.template import get_template_source
|
||||
from dbtemplates.management.commands.sync_templates import (FILES_TO_DATABASE,
|
||||
DATABASE_TO_FILES)
|
||||
|
||||
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.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()))
|
||||
self.assertTrue(Template.objects.filter(name='404.html').exists())
|
||||
|
||||
def test_automatic_sync(self):
|
||||
admin_base_template = get_template_source('admin/base.html')
|
||||
template = Template.objects.create(name='admin/base.html')
|
||||
self.assertEqual(admin_base_template, template.content)
|
||||
|
||||
def test_sync_templates(self):
|
||||
old_template_dirs = settings.TEMPLATE_DIRS
|
||||
temp_template_dir = tempfile.mkdtemp('dbtemplates')
|
||||
last_path_part = temp_template_dir.split('/')[-1]
|
||||
temp_template_path = os.path.join(temp_template_dir, 'temp_test.html')
|
||||
temp_template = codecs.open(temp_template_path, 'w')
|
||||
try:
|
||||
temp_template.write('temp test')
|
||||
settings.TEMPLATE_DIRS = (temp_template_dir,)
|
||||
self.assertFalse(Template.objects.filter(name='temp_test.html').exists())
|
||||
call_command('sync_templates',
|
||||
force=True, verbosity=0, overwrite=FILES_TO_DATABASE)
|
||||
self.assertTrue(Template.objects.filter(name='temp_test.html').exists())
|
||||
|
||||
t = Template.objects.get(name='temp_test.html')
|
||||
t.content = 'temp test modified'
|
||||
t.save()
|
||||
call_command('sync_templates',
|
||||
force=True, verbosity=0, overwrite=DATABASE_TO_FILES)
|
||||
self.assertTrue('modified' in codecs.open(temp_template_path).read())
|
||||
|
||||
call_command('sync_templates',
|
||||
force=True, verbosity=0, delete=True, overwrite=DATABASE_TO_FILES)
|
||||
self.assertTrue(os.path.exists(temp_template_path))
|
||||
self.assertFalse(Template.objects.filter(name='temp_test.html').exists())
|
||||
finally:
|
||||
temp_template.close()
|
||||
settings.TEMPLATE_DIRS = old_template_dirs
|
||||
shutil.rmtree(temp_template_dir)
|
||||
|
|
|
|||
0
dbtemplates/utils/__init__.py
Normal file
0
dbtemplates/utils/__init__.py
Normal file
40
dbtemplates/utils/cache.py
Normal file
40
dbtemplates/utils/cache.py
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
from django.core.cache import get_cache
|
||||
|
||||
from django.contrib.sites.models import Site
|
||||
|
||||
from dbtemplates.conf import settings
|
||||
|
||||
|
||||
def get_cache_backend():
|
||||
return get_cache(settings.CACHE_BACKEND)
|
||||
|
||||
cache = get_cache_backend()
|
||||
|
||||
|
||||
def get_cache_key(name):
|
||||
current_site = Site.objects.get_current()
|
||||
return 'dbtemplates::%s::%s' % (name, current_site.pk)
|
||||
|
||||
|
||||
def set_and_return(cache_key, content, display_name):
|
||||
# Save in cache backend explicitly if manually deleted or invalidated
|
||||
if cache:
|
||||
cache.set(cache_key, content)
|
||||
return (content, display_name)
|
||||
|
||||
|
||||
def add_template_to_cache(instance, **kwargs):
|
||||
"""
|
||||
Called via Django's signals to cache the templates, if the template
|
||||
in the database was added or changed.
|
||||
"""
|
||||
remove_cached_template(instance)
|
||||
cache.set(get_cache_key(instance.name), instance.content)
|
||||
|
||||
|
||||
def remove_cached_template(instance, **kwargs):
|
||||
"""
|
||||
Called via Django's signals to remove cached templates, if the template
|
||||
in the database was changed or deleted.
|
||||
"""
|
||||
cache.delete(get_cache_key(instance.name))
|
||||
106
dbtemplates/utils/settings.py
Normal file
106
dbtemplates/utils/settings.py
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
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_name = "configure_%s" % setting.lower()
|
||||
callback = getattr(self, callback_name, None)
|
||||
if callable(callback):
|
||||
configured_value = callback(configured_value)
|
||||
delattr(self.__class__, setting)
|
||||
setattr(self, prefixed, configured_value)
|
||||
|
|
@ -1,52 +1,7 @@
|
|||
from django import VERSION
|
||||
from django.core.cache import get_cache
|
||||
from django.template import TemplateDoesNotExist
|
||||
from django.utils.importlib import import_module
|
||||
|
||||
from django.contrib.sites.models import Site
|
||||
|
||||
from dbtemplates import settings
|
||||
|
||||
|
||||
def get_cache_backend():
|
||||
return get_cache(settings.CACHE_BACKEND)
|
||||
|
||||
cache = get_cache_backend()
|
||||
|
||||
|
||||
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 settings.ADD_DEFAULT_SITE:
|
||||
current_site = Site.objects.get_current()
|
||||
if current_site not in instance.sites.all():
|
||||
instance.sites.add(current_site)
|
||||
|
||||
|
||||
def get_cache_key(name):
|
||||
current_site = Site.objects.get_current()
|
||||
return 'dbtemplates::%s::%s' % (name, current_site.pk)
|
||||
|
||||
|
||||
def add_template_to_cache(instance, **kwargs):
|
||||
"""
|
||||
Called via Django's signals to cache the templates, if the template
|
||||
in the database was added or changed.
|
||||
"""
|
||||
remove_cached_template(instance)
|
||||
cache.set(get_cache_key(instance.name), instance.content)
|
||||
|
||||
|
||||
def remove_cached_template(instance, **kwargs):
|
||||
"""
|
||||
Called via Django's signals to remove cached templates, if the template
|
||||
in the database was changed or deleted.
|
||||
"""
|
||||
cache.delete(get_cache_key(instance.name))
|
||||
|
||||
|
||||
def get_loaders():
|
||||
from django.template.loader import template_source_loaders
|
||||
|
|
@ -79,6 +34,8 @@ def get_template_source(name):
|
|||
source, origin = load_template_source(name)
|
||||
if source:
|
||||
return source
|
||||
except NotImplementedError:
|
||||
pass
|
||||
except TemplateDoesNotExist:
|
||||
pass
|
||||
if source is None and VERSION[:2] < (1, 2):
|
||||
|
|
@ -1,6 +1,52 @@
|
|||
Changelog
|
||||
=========
|
||||
|
||||
1.1 (07-06-11)
|
||||
--------------
|
||||
|
||||
* **BACKWARDS-INCOMPATIBLE** Requires Django 1.2 or higher.
|
||||
For previous Django versions use an older versions of dbtemplates, e.g.::
|
||||
|
||||
$ pip install django-dbtemplates<1.1
|
||||
|
||||
* Added South migrations.
|
||||
|
||||
.. note::
|
||||
|
||||
If you are using South in your Django project, you can easily enable
|
||||
dbtemplates' migrations, *faking* the first migration by using the
|
||||
``--fake`` option of South's ``migrate`` management command::
|
||||
|
||||
$ manage.py migrate --fake 0001 dbtemplates
|
||||
|
||||
Then run the rest of the migrations::
|
||||
|
||||
$ manage.py migrate dbtemplates
|
||||
|
||||
* Removed uniqueness on the ``name`` field of the ``Template`` model. This is
|
||||
needed because there isn't a ``unique_together`` for M2M fields in Django
|
||||
such as the ``sites`` field in the ``Template`` model.
|
||||
|
||||
* Made the ``sites`` field optional to support a way to apply a template to
|
||||
all sites.
|
||||
|
||||
* Added ``--delete`` option to ``sync_templates`` managment command to delete
|
||||
the file or database entry after syncing (depending on used ``--overwrite``
|
||||
mode).
|
||||
|
||||
* Updated translations.
|
||||
|
||||
* Fixed issue with incorrectly splitting paths in ``sync_templates``.
|
||||
|
||||
* Extended tests.
|
||||
|
||||
* Fixed issue with cache settings handling.
|
||||
|
||||
1.0.1 (04-14-11)
|
||||
----------------
|
||||
|
||||
* Minor bugfixes with regard to the new cache handling.
|
||||
|
||||
1.0 (04-11-11)
|
||||
--------------
|
||||
|
||||
|
|
|
|||
|
|
@ -38,16 +38,16 @@ master_doc = 'index'
|
|||
|
||||
# General information about the project.
|
||||
project = u'django-dbtemplates'
|
||||
copyright = u'2010, Jannis Leidel'
|
||||
copyright = u'2007-2011, Jannis Leidel'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '1.0'
|
||||
version = '1.1'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1.0.1'
|
||||
release = '1.1'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
django-staticfiles
|
||||
south
|
||||
django>=1.3
|
||||
|
|
@ -70,10 +70,10 @@ SECRET_KEY = 'e-%(1e1f8ar2v)_8d!%-75a2ag(w(ht*l%n-wts5$li!5=97)8'
|
|||
|
||||
# List of callables that know how to import templates from various sources.
|
||||
TEMPLATE_LOADERS = (
|
||||
'django.template.loaders.filesystem.load_template_source',
|
||||
'django.template.loaders.app_directories.load_template_source',
|
||||
'django.template.loaders.eggs.load_template_source',
|
||||
'dbtemplates.loader.load_template_source',
|
||||
'django.template.loaders.filesystem.Loader',
|
||||
'django.template.loaders.app_directories.Loader',
|
||||
'django.template.loaders.eggs.Loader',
|
||||
'dbtemplates.loader.Loader',
|
||||
)
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
|
|
@ -98,8 +98,9 @@ INSTALLED_APPS = (
|
|||
'django.contrib.sites',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.flatpages',
|
||||
'django.contrib.staticfiles',
|
||||
'dbtemplates',
|
||||
'staticfiles',
|
||||
'south',
|
||||
#'reversion',
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -16,9 +16,3 @@ urlpatterns = patterns('',
|
|||
# Uncomment the next line to enable the admin:
|
||||
(r'^admin/', include(admin.site.urls)),
|
||||
)
|
||||
|
||||
# the following is used to serve up local media files like images
|
||||
if settings.DEBUG:
|
||||
urlpatterns += patterns("",
|
||||
(r"", include("staticfiles.urls")),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
17
tox.ini
17
tox.ini
|
|
@ -2,7 +2,6 @@
|
|||
downloadcache = .tox/_download/
|
||||
distribute = False
|
||||
envlist =
|
||||
py25-1.1.X, py26-1.1.X, py27-1.1.X,
|
||||
py25-1.2.X, py26-1.2.X, py27-1.2.X,
|
||||
py25-1.3.X, py26-1.3.X, py27-1.3.X
|
||||
|
||||
|
|
@ -10,22 +9,6 @@ envlist =
|
|||
commands =
|
||||
python runtests.py
|
||||
|
||||
[testenv:py25-1.1.X]
|
||||
basepython = python2.5
|
||||
deps =
|
||||
django==1.1.4
|
||||
|
||||
[testenv:py26-1.1.X]
|
||||
basepython = python2.6
|
||||
deps =
|
||||
django==1.1.4
|
||||
|
||||
[testenv:py27-1.1.X]
|
||||
basepython = python2.7
|
||||
deps =
|
||||
django==1.1.4
|
||||
|
||||
|
||||
[testenv:py25-1.2.X]
|
||||
basepython = python2.5
|
||||
deps =
|
||||
|
|
|
|||
Loading…
Reference in a new issue