This commit is contained in:
Michael Kutý 2015-10-16 12:10:34 +00:00
commit 355155e87e
21 changed files with 284 additions and 99 deletions

View file

@ -1,7 +1,7 @@
language: python
python:
- "2.6"
- "2.7"
- 2.6
- 2.7
before_install:
- export DJANGO_SETTINGS_MODULE=dbtemplates.test_settings
install:
@ -13,9 +13,16 @@ script:
- coverage run --branch --source=dbtemplates `which django-admin.py` test dbtemplates
- coverage report --omit="dbtemplates/test*,dbtemplates/migrations*"
env:
- DJANGO=1.3.7
- DJANGO=1.4.5
- DJANGO=1.5.1
- DJANGO=1.7.8
- DJANGO=1.8
matrix:
exclude:
- python: 2.6
env: DJANGO=1.7.8
- python: 2.6
env: DJANGO=1.8
branches:
only:
- develop

View file

@ -20,4 +20,10 @@ The source code and issue tracker can be found on Github:
https://github.com/jezdez/django-dbtemplates
.. _template loader: http://docs.djangoproject.com/en/dev/ref/templates/api/#loader-types
Compatibility Roadmap
---------------------
- 1.3.2 ``dbtemplates`` dropped support for Django < 1.4
- 1.4 will be supported only Django >= 1.7, please freeze your requirements on specific version of ``dbtemplates`` !
.. _template loader: http://docs.djangoproject.com/en/dev/ref/templates/api/#loader-types

View file

@ -1,2 +1,2 @@
# following PEP 386
__version__ = "1.3"
__version__ = "1.3.2"

View file

@ -19,6 +19,7 @@ else:
class CodeMirrorTextArea(forms.Textarea):
"""
A custom widget for the CodeMirror browser editor to be used with the
content field of the Template model.
@ -68,9 +69,13 @@ if settings.DBTEMPLATES_USE_CODEMIRROR and settings.DBTEMPLATES_USE_TINYMCE:
if settings.DBTEMPLATES_USE_TINYMCE:
from tinymce.widgets import AdminTinyMCE
TemplateContentTextArea = AdminTinyMCE
elif settings.DBTEMPLATES_USE_REDACTOR:
from redactor.widgets import RedactorEditor
TemplateContentTextArea = RedactorEditor
class TemplateAdminForm(forms.ModelForm):
"""
Custom AdminForm to make the content textarea wider.
"""
@ -81,6 +86,7 @@ class TemplateAdminForm(forms.ModelForm):
class Meta:
model = Template
fields = ('name', 'content', 'sites', 'creation_date', 'last_changed')
fields = "__all__"
class TemplateAdmin(TemplateModelAdmin):

View file

@ -2,6 +2,7 @@ import posixpath
from django.core.exceptions import ImproperlyConfigured
from django.conf import settings
from django.utils.six import string_types
from appconf import AppConf
@ -10,6 +11,7 @@ class DbTemplatesConf(AppConf):
USE_CODEMIRROR = False
USE_REVERSION = False
USE_TINYMCE = False
USE_REDACTOR = False
ADD_DEFAULT_SITE = True
AUTO_POPULATE_CONTENT = True
MEDIA_PREFIX = None
@ -30,7 +32,7 @@ class DbTemplatesConf(AppConf):
return "dbtemplates"
else:
return "default"
if isinstance(value, basestring) and value.startswith("dbtemplates."):
if isinstance(value, string_types) and value.startswith("dbtemplates."):
raise ImproperlyConfigured("Please upgrade to one of the "
"supported backends as defined "
"in the Django docs.")
@ -49,3 +51,10 @@ class DbTemplatesConf(AppConf):
"INSTALLED_APPS setting to make "
"use of it in dbtemplates.")
return value
def configure_use_redactor(self, value):
if value and 'redactor' not in settings.INSTALLED_APPS:
raise ImproperlyConfigured("Please add 'redactor' to your "
"INSTALLED_APPS setting to make "
"use of it in dbtemplates.")
return value

View file

@ -1,3 +1,4 @@
import django
from django.contrib.sites.models import Site
from django.db import router
from django.template import TemplateDoesNotExist
@ -5,10 +6,14 @@ from django.template import TemplateDoesNotExist
from dbtemplates.models import Template
from dbtemplates.utils.cache import (cache, get_cache_key,
set_and_return, get_cache_notfound_key)
from django.template.loader import BaseLoader
if django.get_version() >= '1.8':
from django.template.loaders.base import Loader as tLoaderCls
else:
from django.template.loader import BaseLoader as tLoaderCls # noqa
class Loader(BaseLoader):
class Loader(tLoaderCls):
"""
A custom template loader to load templates from the database.

View file

@ -16,7 +16,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
#"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"

View file

@ -1,16 +1,31 @@
import os
import codecs
from optparse import make_option
from django import VERSION
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
try:
from django.utils.six import input as raw_input
except ImportError:
pass
from dbtemplates.conf import settings
from dbtemplates.models import Template
ALWAYS_ASK, FILES_TO_DATABASE, DATABASE_TO_FILES = ('0', '1', '2')
DIRS = []
if VERSION[:2] < (1, 8):
from django.template.loaders.app_directories import app_template_dirs
DIRS = settings.TEMPLATE_DIRS
else:
from django.template.utils import get_app_template_dirs
from django.template.loader import _engine_list
for engine in _engine_list():
DIRS.extend(engine.dirs)
app_template_dirs = get_app_template_dirs('templates')
class Command(NoArgsCommand):
help = "Syncs file system templates with the database bidirectionally."
@ -56,9 +71,9 @@ class Command(NoArgsCommand):
"list or tuple.")
if app_first:
tpl_dirs = app_template_dirs + settings.TEMPLATE_DIRS
tpl_dirs = app_template_dirs + DIRS
else:
tpl_dirs = settings.TEMPLATE_DIRS + app_template_dirs
tpl_dirs = DIRS + app_template_dirs
templatedirs = [d for d in tpl_dirs if os.path.isdir(d)]
for templatedir in templatedirs:
@ -103,7 +118,8 @@ class Command(NoArgsCommand):
try:
os.remove(path)
except OSError:
raise CommandError(u"Couldn't delete %s" % path)
raise CommandError(
u"Couldn't delete %s" % path)
elif confirm == DATABASE_TO_FILES:
f = codecs.open(path, 'w', 'utf-8')
try:

View file

@ -1,55 +1,71 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import django
from django.db import models, migrations
import django.utils.timezone
class Migration(SchemaMigration):
class Migration(migrations.Migration):
def forwards(self, orm):
dependencies = [
('sites', '0001_initial'),
]
# 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']
if django.get_version() >= '1.8':
operations = [
migrations.CreateModel(
name='Template',
fields=[
('id', models.AutoField(
verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(
help_text="Example: 'flatpages/default.html'", max_length=100, verbose_name='name')),
('content', models.TextField(verbose_name='content', blank=True)),
('creation_date', models.DateTimeField(
default=django.utils.timezone.now, verbose_name='creation date')),
('last_changed', models.DateTimeField(
default=django.utils.timezone.now, verbose_name='last changed')),
('sites', models.ManyToManyField(
to='sites.Site', verbose_name='sites', blank=True)),
],
options={
'ordering': ('name',),
'db_table': 'django_template',
'verbose_name': 'template',
'verbose_name_plural': 'templates',
},
bases=(models.Model,),
managers = [
('objects', django.db.models.manager.Manager()),
('on_site', django.contrib.sites.managers.CurrentSiteManager(
b'sites')),
],
),
]
else:
operations = [
migrations.CreateModel(
name='Template',
fields=[
('id', models.AutoField(
verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(
help_text="Example: 'flatpages/default.html'", max_length=100, verbose_name='name')),
('content', models.TextField(verbose_name='content', blank=True)),
('creation_date', models.DateTimeField(
default=django.utils.timezone.now, verbose_name='creation date')),
('last_changed', models.DateTimeField(
default=django.utils.timezone.now, verbose_name='last changed')),
('sites', models.ManyToManyField(
to='sites.Site', verbose_name='sites', blank=True)),
],
options={
'ordering': ('name',),
'db_table': 'django_template',
'verbose_name': 'template',
'verbose_name_plural': 'templates',
},
bases=(models.Model,),
),
]

View file

@ -1,16 +1,15 @@
# -*- coding: utf-8 -*-
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
from django.contrib.sites.managers import CurrentSiteManager
from django.contrib.sites.models import Site
from django.db import models
from django.db.models import signals
from django.template import TemplateDoesNotExist
from django.utils.translation import ugettext_lazy as _
from django.contrib.sites.models import Site
from django.contrib.sites.managers import CurrentSiteManager
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
try:
from django.utils.timezone import now
except ImportError:
@ -27,7 +26,7 @@ class Template(models.Model):
help_text=_("Example: 'flatpages/default.html'"))
content = models.TextField(_('content'), blank=True)
sites = models.ManyToManyField(Site, verbose_name=_(u'sites'),
blank=True, null=True)
blank=True)
creation_date = models.DateTimeField(_('creation date'),
default=now)
last_changed = models.DateTimeField(_('last changed'),

View file

@ -0,0 +1,55 @@
# 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']

View file

View file

@ -106,6 +106,11 @@ class DbTemplatesTestCase(TestCase):
try:
temp_template.write('temp test')
settings.TEMPLATE_DIRS = (temp_template_dir,)
# these works well if is not settings patched at runtime
# for supporting django < 1.7 tests we must patch dirs in runtime
from dbtemplates.management.commands import sync_templates
sync_templates.DIRS = settings.TEMPLATE_DIRS
self.assertFalse(
Template.objects.filter(name='temp_test.html').exists())
call_command('sync_templates', force=True,

View file

@ -1,3 +1,6 @@
import django
DBTEMPLATES_CACHE_BACKEND = 'dummy://'
DATABASE_ENGINE = 'sqlite3'
@ -23,10 +26,16 @@ INSTALLED_APPS = [
'dbtemplates',
]
MIDDLEWARE_CLASSES = (
'django.contrib.messages.middleware.MessageMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
)
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
'dbtemplates.loader.Loader',
)
TEST_RUNNER = 'discover_runner.DiscoverRunner'
if django.get_version() <= '1.6':
TEST_RUNNER = 'discover_runner.DiscoverRunner'

View file

@ -1,5 +1,4 @@
from django.core.cache import get_cache
from django.core import signals
from django.contrib.sites.models import Site
from django.template.defaultfilters import slugify
@ -7,7 +6,22 @@ from dbtemplates.conf import settings
def get_cache_backend():
return get_cache(settings.DBTEMPLATES_CACHE_BACKEND)
"""
Compatibilty wrapper for getting Django's cache backend instance
"""
try:
from django.core.cache import _create_cache
except ImportError:
# Django < 1.7
from django.core.cache import get_cache as _get_cache
return _get_cache(settings.DBTEMPLATES_CACHE_BACKEND)
cache = _create_cache(settings.DBTEMPLATES_CACHE_BACKEND)
# Some caches -- python-memcached in particular -- need to do a cleanup at the
# end of a request cycle. If not implemented in a particular backend
# cache.close is a no-op
signals.request_finished.connect(cache.close)
return cache
cache = get_cache_backend()

View file

@ -5,18 +5,25 @@ from django.utils.importlib import import_module
def get_loaders():
from django.template.loader import template_source_loaders
if template_source_loaders is None:
try:
from django.template.loader import find_template as finder
except ImportError:
from django.template.loader import find_template_source as finder # noqa
try:
source, name = finder('test')
except TemplateDoesNotExist:
pass
if VERSION[:2] < (1, 8):
from django.template.loader import template_source_loaders
return template_source_loaders or []
if template_source_loaders is None:
try:
from django.template.loader import find_template as finder
except ImportError:
from django.template.loader import find_template_source as finder # noqa
try:
source, name = finder('test')
except TemplateDoesNotExist:
pass
from django.template.loader import template_source_loaders
return template_source_loaders or []
else:
from django.template.loader import _engine_list
loaders = []
for engine in _engine_list():
loaders.extend(engine.engine.template_loaders)
return loaders
def get_template_source(name):
@ -26,7 +33,8 @@ def get_template_source(name):
# Don't give a damn about dbtemplates' own loader.
continue
module = import_module(loader.__module__)
load_template_source = getattr(module, 'load_template_source', None)
load_template_source = getattr(
module, 'load_template_source', None)
if load_template_source is None:
load_template_source = loader.load_template_source
try:
@ -52,6 +60,6 @@ def get_template_source(name):
def check_template_syntax(template):
try:
Template(template.content)
except TemplateSyntaxError, e:
except TemplateSyntaxError as e:
return (False, e)
return (True, None)

View file

@ -1,6 +1,14 @@
Changelog
=========
v1.3.2 (2015-06-15)
-------------------
* support for Django 1.8 (not full, but usable)
* support for RedactorJS
thanks for contrib - @eculver, @kmooney, @volksman
v1.3.1 (2012-05-23)
-------------------

View file

@ -24,21 +24,41 @@ Setup
'dbtemplates',
)
* Add ``dbtemplates.loader.Loader`` to the ``TEMPLATE_LOADERS`` list
* Add ``dbtemplates.loader.Loader`` to the ``TEMPLATES.OPTIONS.loaders`` list
in the settings.py of your Django project.
It should look something like this::
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
'dbtemplates.loader.Loader',
)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [ # your template dirs here
],
'APP_DIRS': False,
'OPTIONS': {
'context_processors': [
'django.contrib.auth.context_processors.auth',
'django.template.context_processors.debug',
'django.template.context_processors.i18n',
'django.template.context_processors.media',
'django.template.context_processors.static',
'django.template.context_processors.tz',
'django.contrib.messages.context_processors.messages',
'django.template.context_processors.request',
],
'loaders': [
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
'dbtemplates.loader.Loader',
],
},
},
]
Order of TEMPLATE_LOADERS is important. In the former example, templates from database
Order of ``TEMPLATES.OPTIONS.loaders`` is important. In the former example, templates from database
will be used as a fallback (ie. when template does not exists in other locations).
If you want template from database to be used to override templates in other locations,
put ``dbtemplates.loader.Loader`` at beginning of ``TEMPLATE_LOADERS`` settting.
put ``dbtemplates.loader.Loader`` at beginning of ``loaders``.
4. Sync your database ``python manage.py syncdb``
5. Restart your Django server

View file

@ -5,7 +5,9 @@ from setuptools import setup, find_packages
def read(*parts):
return codecs.open(os.path.join(os.path.dirname(__file__), *parts)).read()
filename = os.path.join(os.path.dirname(__file__), *parts)
with codecs.open(filename, encoding='utf-8') as fp:
return fp.read()
def find_version(*file_paths):