Compare commits

..

No commits in common. "master" and "0.7.2" have entirely different histories.

89 changed files with 1592 additions and 2849 deletions

View file

@ -1,6 +0,0 @@
[run]
source = dbtemplates
branch = 1
[report]
omit = *tests*,*/migrations/*,test_*

View file

@ -1,40 +0,0 @@
name: Release
on:
push:
tags:
- '*'
jobs:
build:
if: github.repository == 'jazzband/django-dbtemplates'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
- name: Install dependencies
run: |
python -m pip install -U pip
python -m pip install -U setuptools twine wheel
- name: Build package
run: |
python setup.py --version
python setup.py sdist --format=gztar bdist_wheel
twine check dist/*
- name: Upload packages to Jazzband
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
uses: pypa/gh-action-pypi-publish@release/v1
with:
user: jazzband
password: ${{ secrets.JAZZBAND_RELEASE_KEY }}
repository_url: https://jazzband.co/projects/django-dbtemplates/upload

View file

@ -1,48 +0,0 @@
name: Test
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
max-parallel: 5
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11', '3.13']
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Get pip cache dir
id: pip-cache
run: |
echo "::set-output name=dir::$(pip cache dir)"
- name: Cache
uses: actions/cache@v3
with:
path: ${{ steps.pip-cache.outputs.dir }}
key:
${{ matrix.python-version }}-v1-${{ hashFiles('**/setup.py') }}-${{ hashFiles('**/tox.ini') }}
restore-keys: |
${{ matrix.python-version }}-v1-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install --upgrade tox tox-gh-actions
- name: Tox tests
run: |
tox -v
- name: Upload coverage
uses: codecov/codecov-action@v2
with:
name: Python ${{ matrix.python-version }}

10
.gitignore vendored
View file

@ -1,14 +1,6 @@
.*
!.gitignore
!.coveragerc
*.pyc
.*.swp
MANIFEST
build
dist
*.egg-info
docs/_build
.tox/
*.egg/
.coverage
coverage.xml
*.egg-info

9
.hgignore Normal file
View file

@ -0,0 +1,9 @@
syntax: glob
*.pyc
.*.swp
MANIFEST
build
dist
django_dbtemplates.egg-info/
example/example.db
docs/_build

24
.hgtags Normal file
View file

@ -0,0 +1,24 @@
bd537cd8beba30f1a26328e02126d3d1b14ebf8f 0.2.5
1b426859f05b8a003411964883ed5d42ec6c1b01 0.3.0
97da228cc698bfae05f60a68ec978030722b0777 0.3.1
50c69325d3758d2e82541b13be2794ebbe9ee449 0.4.0
d35a41ea96d3604a3c2654590c5c76b8865c4251 0.4.1
a4bd56a7c2ea4c6f16a726e47bb185101934fe08 0.4.2
447247c1ce1fbc77ac79c5855630af306f4f8c42 0.4.3
5b2e4f7fc267daf71325991e913f98e6f96259bb 0.4.4
ea4d636f3459ddbb51d87e921cf23f87e41d658d 0.4.5
9a30f34bc5b07376ed6752eed94d9d58e791fbac 0.4.6
9dc2a0e48494d6a354f5ca25db31638cede4bae4 0.4.7
a3be97628ed8633e2fe232e6680474e7fd3e9fea 0.5.0
bf3db2fe192d4a02bf531e61e23df342c36d6b1b 0.5.1
67a86cf9f7c8ac8d9da855c13abbef2547033cce 0.5.2
6967bbbee378f470e4b1df02b57112dd050d424b 0.5.3
5965315c03c1a8c1cfb34752cca3802d68156e27 0.5.4
4109e0db4340042cb85ea8a7d2b6ce37245738c6 0.5.5
ade167225d06cb6888ea8bfa84e7d020590171c6 0.5.6
dff01be9c8af328f8fcbc2fc97edcbe8d97840e2 0.5.7
f8f7eaf275c5e8ac52174642265af55691abef7c 0.5.8
4b36382cdfd756f45f81b0d042aaf331c3eabe30 0.6.0
0ac352fec2c2a03ac801ff0c40f0649ef16e1f64 0.6.1
34a0511928629872ce8cc5f94c6bed65f82ac343 0.7.0
74c22fa8c4a64ea37f9b6b2515a4162b8b8b1a2a 0.7.1

View file

@ -1,15 +0,0 @@
repos:
- repo: https://github.com/asottile/pyupgrade
rev: v2.34.0
hooks:
- id: pyupgrade
args: [--py37-plus]
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
hooks:
- id: check-merge-conflict
- id: check-yaml
ci:
autoupdate_schedule: quarterly

View file

@ -1,25 +0,0 @@
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Set the version of Python and other tools you might need
build:
os: ubuntu-20.04
tools:
python: "3.9"
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py
# If using Sphinx, optionally build your docs in additional formats such as PDF
formats:
- pdf
# Optionally declare the Python requirements required to build your docs
python:
install:
- requirements: requirements/docs.txt

View file

@ -1,7 +0,0 @@
[django-dbtemplates.main]
file_filter = dbtemplates/locale/<lang>/LC_MESSAGES/django.po
source_file = dbtemplates/locale/en/LC_MESSAGES/django.po
source_lang = en
[main]
host = https://www.transifex.com

18
AUTHORS
View file

@ -1,18 +0,0 @@
Alen Mujezinovic
Alex Gaynor
Alex Kamedov
Alexander Artemenko
Arne Brodowski
David Paccoud
Diego Búrigo Zacarão
Dmitry Falk
Jannis Leidel
Jure Cuhalev
Jason Mayfield
Kevin Mooney
Mark Stahler
Matt Dorn
Oliver George
Selwin Ong
Stephan Peijnik <spe@anexia.at>, ANEXIA Internetdienstleistungs GmbH, http://www.anexia.at/
Zhang Kun

View file

@ -1,46 +0,0 @@
# Code of Conduct
As contributors and maintainers of the Jazzband projects, and in the interest of
fostering an open and welcoming community, we pledge to respect all people who
contribute through reporting issues, posting feature requests, updating documentation,
submitting pull requests or patches, and other activities.
We are committed to making participation in the Jazzband a harassment-free experience
for everyone, regardless of the level of experience, gender, gender identity and
expression, sexual orientation, disability, personal appearance, body size, race,
ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery
- Personal attacks
- Trolling or insulting/derogatory comments
- Public or private harassment
- Publishing other's private information, such as physical or electronic addresses,
without explicit permission
- Other unethical or unprofessional conduct
The Jazzband roadies have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are not
aligned to this Code of Conduct, or to ban temporarily or permanently any contributor
for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
By adopting this Code of Conduct, the roadies commit themselves to fairly and
consistently applying these principles to every aspect of managing the jazzband
projects. Roadies who do not follow or enforce the Code of Conduct may be permanently
removed from the Jazzband roadies.
This code of conduct applies both within project spaces and in public spaces when an
individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by
contacting the roadies at `roadies@jazzband.co`. All complaints will be reviewed and
investigated and will result in a response that is deemed necessary and appropriate to
the circumstances. Roadies are obligated to maintain confidentiality with regard to the
reporter of an incident.
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version
1.3.0, available at [https://contributor-covenant.org/version/1/3/0/][version]
[homepage]: https://contributor-covenant.org
[version]: https://contributor-covenant.org/version/1/3/0/

View file

@ -1,3 +0,0 @@
[![Jazzband](https://jazzband.co/static/img/jazzband.svg)](https://jazzband.co/)
This is a [Jazzband](https://jazzband.co/) project. By contributing you agree to abide by the [Contributor Code of Conduct](https://jazzband.co/docs/conduct) and follow the [guidelines](https://jazzband.co/docs/guidelines).

17
INSTALL Normal file
View file

@ -0,0 +1,17 @@
To install it, run the following command inside this directory:
python setup.py install
Or if you'd prefer you can simply place the included ``dbtemplates``
directory somewhere on your Python path, or symlink to it from
somewhere on your Python path; this is useful if you're working from a
Subversion checkout. Since ``dbtemplates`` is registered in the
Python Package Index you can also run ``easy_install django-dbtemplates``
or ``pip install django-dbtemplates`` optionally.
Note that this application requires Python 2.3 or later, and a recent
Subversion checkout of Django. You can obtain Python from
http://www.python.org/ and Django from http://www.djangoproject.com/.
This install notice was bluntly stolen from James Bennett's registration
package, http://www.bitbucket.org/ubernostrum/django-registration/

View file

@ -1,4 +1,4 @@
Copyright (c) 2007-2019, Jannis Leidel and contributors
Copyright (c) 2007-2010, Jannis Leidel and contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without

View file

@ -1,4 +1,7 @@
include LICENSE AUTHORS README.rst MANIFEST.in tox.ini .coveragerc CONTRIBUTING.md
include INSTALL
include LICENSE
include README.rst
include MANIFEST.in
recursive-include docs *.txt
recursive-include dbtemplates/locale *
recursive-include dbtemplates/static/dbtemplates *.css *.js
recursive-include dbtemplates/media/dbtemplates *.css *.js

View file

@ -1,30 +1,15 @@
django-dbtemplates
==================
===================================
Database template loader for Django
===================================
.. image:: https://jazzband.co/static/img/badge.svg
:alt: Jazzband
:target: https://jazzband.co/
``dbtemplates`` is a Django app that comes with to parts: It allows you to
create templates that are saved in your database, and it provides a so called
`template loader`_, a function that enables Django to find the templates you
created in the database.
.. image:: https://github.com/jazzband/django-dbtemplates/workflows/Test/badge.svg
:target: https://github.com/jazzband/django-dbtemplates/actions
It also includes a extensible caching mechanism and supports version control
of the templates saved in the database.
.. image:: https://codecov.io/github/jazzband/django-dbtemplates/coverage.svg?branch=master
:alt: Codecov
:target: https://codecov.io/github/jazzband/django-dbtemplates?branch=master
Please see ``docs/overview.txt`` for more details.
``dbtemplates`` is a Django app that consists of two parts:
1. It allows you to store templates in your database
2. It provides `template loader`_ that enables Django to load the
templates from the database
It also features optional support for versioned storage and django-admin
command, integrates with Django's caching system and the admin actions.
Please see https://django-dbtemplates.readthedocs.io/ for more details.
The source code and issue tracker can be found on Github:
https://github.com/jazzband/django-dbtemplates
.. _template loader: http://docs.djangoproject.com/en/dev/ref/templates/api/#loader-types
.. _template loader: http://docs.djangoproject.com/en/dev/ref/templates/api/#loader-types

View file

@ -1,3 +1 @@
import importlib.metadata
__version__ = importlib.metadata.version("django-dbtemplates")
__version__ = "0.7.2"

View file

@ -1,44 +1,35 @@
import posixpath
from django import forms
from django.conf import settings
from django.contrib import admin
from django.core.exceptions import ImproperlyConfigured
from django.utils.translation import gettext_lazy as _
from django.utils.translation import ngettext
from django.utils.translation import ungettext, ugettext_lazy as _
from django.utils.safestring import mark_safe
from dbtemplates.conf import settings
from dbtemplates.models import Template, add_template_to_cache, remove_cached_template
from dbtemplates.utils.template import check_template_syntax
from dbtemplates.settings import MEDIA_PREFIX, USE_REVERSION, USE_CODEMIRROR
from dbtemplates.models import Template, backend, remove_cached_template, \
add_template_to_cache
# Check if either django-reversion-compare or django-reversion is installed and
# use reversion_compare's CompareVersionAdmin or reversion's VersionAdmin as
# the base admin class if yes
if settings.DBTEMPLATES_USE_REVERSION_COMPARE:
from reversion_compare.admin import CompareVersionAdmin \
as TemplateModelAdmin
elif settings.DBTEMPLATES_USE_REVERSION:
# Check if django-reversion is installed and use reversions' VersionAdmin
# as the base admin class if yes
if USE_REVERSION:
from reversion.admin import VersionAdmin as TemplateModelAdmin
else:
from django.contrib.admin import ModelAdmin as TemplateModelAdmin # noqa
from django.contrib.admin import ModelAdmin as TemplateModelAdmin
class CodeMirrorTextArea(forms.Textarea):
"""
A custom widget for the CodeMirror browser editor to be used with the
A custom widget for the CodeMirror browser editor to be used with the
content field of the Template model.
"""
class Media:
css = dict(screen=[posixpath.join(
settings.DBTEMPLATES_MEDIA_PREFIX, 'css/editor.css')])
js = [posixpath.join(settings.DBTEMPLATES_MEDIA_PREFIX,
'js/codemirror.js')]
css = dict(screen=[posixpath.join(MEDIA_PREFIX, 'css/editor.css')])
js = [posixpath.join(MEDIA_PREFIX, 'js/codemirror.js')]
def render(self, name, value, attrs=None, renderer=None):
def render(self, name, value, attrs=None):
result = []
result.append(
super().render(name, value, attrs))
result.append("""
super(CodeMirrorTextArea, self).render(name, value, attrs))
result.append(u"""
<script type="text/javascript">
var editor = CodeMirror.fromTextArea('id_%(name)s', {
path: "%(media_prefix)sjs/",
@ -51,53 +42,31 @@ class CodeMirrorTextArea(forms.Textarea):
lineNumbers: true
});
</script>
""" % dict(media_prefix=settings.DBTEMPLATES_MEDIA_PREFIX, name=name))
return mark_safe("".join(result))
""" % dict(media_prefix=MEDIA_PREFIX, name=name))
return mark_safe(u"".join(result))
if settings.DBTEMPLATES_USE_CODEMIRROR:
if USE_CODEMIRROR:
TemplateContentTextArea = CodeMirrorTextArea
else:
TemplateContentTextArea = forms.Textarea
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.")
else:
content_help_text = ""
if settings.DBTEMPLATES_USE_CODEMIRROR and settings.DBTEMPLATES_USE_TINYMCE:
raise ImproperlyConfigured("You may use either CodeMirror or TinyMCE "
"with dbtemplates, not both. Please disable "
"one of them.")
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.
"""
content = forms.CharField(
widget=TemplateContentTextArea(attrs={'rows': '24'}),
help_text=content_help_text, required=False)
widget=TemplateContentTextArea({'rows': '24'}),
help_text=_("Leaving this empty causes Django to look for a template "
"with the given name and populate this field with its content."),
required=False)
class Meta:
model = Template
fields = ('name', 'content', 'sites', 'creation_date', 'last_changed')
fields = "__all__"
class TemplateAdmin(TemplateModelAdmin):
form = TemplateAdminForm
readonly_fields = ['creation_date', 'last_changed']
fieldsets = (
(None, {
'fields': ('name', 'content'),
@ -105,69 +74,47 @@ class TemplateAdmin(TemplateModelAdmin):
}),
(_('Advanced'), {
'fields': (('sites'),),
'classes': ('collapse',),
}),
(_('Date/time'), {
'fields': (('creation_date', 'last_changed'),),
'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', 'check_syntax']
if backend:
actions = ['invalidate_cache', 'repopulate_cache']
def invalidate_cache(self, request, queryset):
if not backend:
self.message_user(request, ("There is no active cache backend."))
return
for template in queryset:
remove_cached_template(template)
count = queryset.count()
message = ngettext(
message = ungettext(
"Cache of one template successfully invalidated.",
"Cache of %(count)d templates successfully invalidated.",
count)
self.message_user(request, message % {'count': count})
invalidate_cache.short_description = _("Invalidate cache of "
"selected templates")
len(queryset))
self.message_user(request, message % {'count': len(queryset)})
invalidate_cache.short_description = _("Invalidate cache of selected templates")
def repopulate_cache(self, request, queryset):
if not backend:
self.message_user(request, ("There is no active cache backend."))
return
for template in queryset:
add_template_to_cache(template)
count = queryset.count()
message = ngettext(
message = ungettext(
"Cache successfully repopulated with one template.",
"Cache successfully repopulated with %(count)d templates.",
count)
self.message_user(request, message % {'count': count})
repopulate_cache.short_description = _("Repopulate cache with "
"selected templates")
def check_syntax(self, request, queryset):
errors = []
for template in queryset:
valid, error = check_template_syntax(template)
if not valid:
errors.append(f'{template.name}: {error}')
if errors:
count = len(errors)
message = ngettext(
"Template syntax check FAILED for %(names)s.",
"Template syntax check FAILED for "
"%(count)d templates: %(names)s.",
count)
self.message_user(request, message %
{'count': count, 'names': ', '.join(errors)})
else:
count = queryset.count()
message = ngettext(
"Template syntax OK.",
"Template syntax OK for %(count)d templates.", count)
self.message_user(request, message % {'count': count})
check_syntax.short_description = _("Check template syntax")
len(queryset))
self.message_user(request, message % {'count': len(queryset)})
repopulate_cache.short_description = _("Repopulate cache with selected templates")
def site_list(self, template):
return ", ".join([site.name for site in template.sites.all()])
return ", ".join([site.name for site in template.sites.all()])
site_list.short_description = _('sites')
admin.site.register(Template, TemplateAdmin)

View file

@ -1,9 +0,0 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class DBTemplatesConfig(AppConfig):
name = 'dbtemplates'
verbose_name = _('Database templates')
default_auto_field = 'django.db.models.AutoField'

102
dbtemplates/cache.py Normal file
View file

@ -0,0 +1,102 @@
import os
from django.conf import settings
from django.core.cache import cache
from django.core.exceptions import ImproperlyConfigured
from django.utils.encoding import force_unicode
class BaseCacheBackend(object):
"""
Base class for custom cache backend of dbtemplates to be used while
subclassing.
Set DBTEMPLATES_CACHE_BACKEND setting to the Python path to that subclass.
"""
def _site(self):
from django.contrib.sites.models import Site
return Site.objects.get_current()
site = property(_site)
def load(self, name):
"""
Loads a template from the cache with the given name.
"""
raise NotImplemented
def save(self, name, content):
"""
Saves the given template content with the given name in the cache.
"""
raise NotImplemented
def remove(self, name):
"""
Removes the template with the given name from the cache.
"""
raise NotImplemented
class DjangoCacheBackend(BaseCacheBackend):
"""
A cache backend that uses Django's cache mechanism.
"""
def _cache_key(self, name):
return 'dbtemplates::%s::%s' % (name, self.site.pk)
def load(self, name):
cache_key = self._cache_key(name)
return cache.get(cache_key)
def save(self, name, content):
cache_key = self._cache_key(name)
cache.set(cache_key, content)
def remove(self, name):
cache_key = self._cache_key(name)
cache.delete(cache_key)
class FileSystemBackend(BaseCacheBackend):
"""
A cache backend that uses simple files to hold the template cache.
"""
def __init__(self):
try:
self.cache_dir = getattr(settings, 'DBTEMPLATES_CACHE_DIR', None)
self.cache_dir = os.path.normpath(self.cache_dir)
if not os.path.isdir(self.cache_dir):
pass
except:
raise ImproperlyConfigured(
"You're using the dbtemplates file system cache backend "
"without having set the DBTEMPLATES_CACHE_DIR setting to a "
"valid value. Make sure the directory exists and is writeable "
"for the user your Django instance is running with."
)
super(FileSystemBackend, self).__init__()
def _filepath(self, name):
return os.path.join(self.cache_dir, self.site.domain, name)
def load(self, name):
try:
filepath = self._filepath(name)
return open(filepath).read().decode('utf-8')
except:
return None
def save(self, name, content, retry=False):
try:
filepath = self._filepath(name)
dirname = os.path.dirname(filepath)
if not os.path.exists(dirname):
os.makedirs(dirname)
cache_file = open(filepath, 'w')
cache_file.write(force_unicode(content).encode('utf-8'))
cache_file.close()
except Exception:
raise
def remove(self, name):
try:
filepath = self._filepath(name)
os.remove(filepath)
except:
pass

View file

@ -1,67 +0,0 @@
import posixpath
from django.core.exceptions import ImproperlyConfigured
from django.conf import settings
from appconf import AppConf
class DbTemplatesConf(AppConf):
USE_CODEMIRROR = False
USE_REVERSION = False
USE_REVERSION_COMPARE = False
USE_TINYMCE = False
USE_REDACTOR = 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(settings, "STATIC_URL", None)
if base_url is None:
base_url = settings.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(settings, "CACHES"):
if "dbtemplates" in settings.CACHES:
return "dbtemplates"
else:
return "default"
if isinstance(value, str) 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 settings.INSTALLED_APPS:
raise ImproperlyConfigured("Please add 'reversion' to your "
"INSTALLED_APPS setting to make "
"use of it in dbtemplates.")
return value
def configure_use_reversion_compare(self, value):
if value and 'reversion_compare' not in settings.INSTALLED_APPS:
raise ImproperlyConfigured("Please add 'reversion_compare' to your"
" INSTALLED_APPS setting to make "
"use of it in dbtemplates.")
return value
def configure_use_tinymce(self, value):
if value and 'tinymce' not in settings.INSTALLED_APPS:
raise ImproperlyConfigured("Please add 'tinymce' to your "
"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,14 +1,11 @@
from django import VERSION
from django.conf import settings
from django.contrib.sites.models import Site
from django.db import router
from django.template import Origin, TemplateDoesNotExist
from django.template.loaders.base import Loader as BaseLoader
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 dbtemplates.models import Template, backend
class Loader(BaseLoader):
def load_template_source(template_name, template_dirs=None):
"""
A custom template loader to load templates from the database.
@ -17,71 +14,45 @@ class Loader(BaseLoader):
it falls back to query the database field ``name`` with the template path
and ``sites`` with the current site.
"""
is_usable = True
def get_template_sources(self, template_name, template_dirs=None):
yield Origin(
name=template_name,
template_name=template_name,
loader=self,
if VERSION[:2] >= (1, 2):
# For backward compatibility
import warnings
warnings.warn(
"`dbtemplates.loader.load_template_source` is deprecated; "
"use `dbtemplates.loader.Loader` instead.",
PendingDeprecationWarning
)
def get_contents(self, origin):
content, _ = self._load_template_source(origin.template_name)
return content
def _load_and_store_template(self, template_name, cache_key, site,
**params):
template = Template.objects.get(name__exact=template_name, **params)
db = router.db_for_read(Template, instance=template)
display_name = f'dbtemplates:{db}:{template_name}:{site.domain}'
return set_and_return(cache_key, template.content, display_name)
def _load_template_source(self, template_name, template_dirs=None):
# The logic should work like this:
# * Try to find the template in the cache. If found, return it.
# * Now check the cache if a lookup for the given template
# has failed lately and hand over control to the next template
# loader waiting in line.
# * If this still did not fail we first try to find a site-specific
# template in the database.
# * On a failure from our last attempt we try to load the global
# template from the database.
# * If all of the above steps have failed we generate a new key
# in the cache indicating that queries failed, with the current
# timestamp.
site = Site.objects.get_current()
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 Exception:
pass
# Not found in cache, move on.
cache_notfound_key = get_cache_notfound_key(template_name)
if cache:
try:
notfound = cache.get(cache_notfound_key)
if notfound:
raise TemplateDoesNotExist(template_name)
except Exception:
raise TemplateDoesNotExist(template_name)
# Not marked as not-found, move on...
site = Site.objects.get_current()
display_name = 'db:%s:%s:%s' % (settings.DATABASE_ENGINE,
template_name, site.domain)
if backend:
try:
return self._load_and_store_template(template_name, cache_key,
site, sites__in=[site.id])
except (Template.MultipleObjectsReturned, Template.DoesNotExist):
try:
return self._load_and_store_template(template_name, cache_key,
site, sites__isnull=True)
except (Template.MultipleObjectsReturned, Template.DoesNotExist):
pass
backend_template = backend.load(template_name)
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
if backend:
backend.save(template_name, 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)
# Mark as not-found in cache.
cache.set(cache_notfound_key, '1')
raise TemplateDoesNotExist(template_name)

View file

@ -1,108 +1,84 @@
# SOME DESCRIPTIVE TITLE.
# django-dbtemplates in Danish.
# django-dbtemplates på Dansk.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Michael Lind Mortensen <illio@cs.au.dk>, 2009.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: django-dbtemplates\n"
"Report-Msgid-Bugs-To: https://github.com/jezdez/django-dbtemplates/issues\n"
"POT-Creation-Date: 2011-08-15 13:13+0200\n"
"PO-Revision-Date: 2011-08-15 11:14+0000\n"
"Last-Translator: Jannis <jannis@leidel.info>\n"
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-10-09 13:45+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"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: da\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: admin.py:56
#: admin.py:29
msgid ""
"Leaving this empty causes Django to look for a template with the given name "
"and populate this field with its content."
msgstr ""
"Hvis du efterlader dette felt tomt, så vil Django søge efter en template med"
" det givne navn og udfylde dette felt med dets indhold."
"Hvis du efterlader dette felt tomt, så vil Django søge efter en template med "
"det givne navn og udfylde dette felt med dets indhold."
#: admin.py:82
msgid "Advanced"
msgstr ""
#: admin.py:85
#: admin.py:43
msgid "Date/time"
msgstr "Dato/tid"
#: admin.py:102
#: admin.py:61
#, python-format
msgid "Cache of one template successfully invalidated."
msgid_plural "Cache of %(count)d templates successfully invalidated."
msgstr[0] ""
msgstr[1] ""
#: admin.py:106
#: admin.py:65
msgid "Invalidate cache of selected templates"
msgstr ""
#: admin.py:114
#: admin.py:74
#, python-format
msgid "Cache successfully repopulated with one template."
msgid_plural "Cache successfully repopulated with %(count)d templates."
msgstr[0] ""
msgstr[1] ""
#: admin.py:118
#: admin.py:78
msgid "Repopulate cache with selected templates"
msgstr ""
#: admin.py:130
#, python-format
msgid "Template syntax check FAILED for %(names)s."
msgid_plural ""
"Template syntax check FAILED for %(count)d templates: %(names)s."
msgstr[0] ""
msgstr[1] ""
#: admin.py:138
#, python-format
msgid "Template syntax OK."
msgid_plural "Template syntax OK for %(count)d templates."
msgstr[0] ""
msgstr[1] ""
#: admin.py:141
msgid "Check template syntax"
msgstr ""
#: admin.py:145 models.py:25
#: admin.py:82
msgid "sites"
msgstr "websider"
#: models.py:22
#: models.py:18
msgid "name"
msgstr "navn"
#: models.py:23
#: models.py:19
msgid "Example: 'flatpages/default.html'"
msgstr "Eksempel: 'flatpages/default.html'"
#: models.py:24
#: models.py:20
msgid "content"
msgstr "indhold"
#: models.py:27
#: models.py:22
msgid "creation date"
msgstr "oprettelsesdato"
#: models.py:29
#: models.py:24
msgid "last changed"
msgstr "sidst ændret"
#: models.py:37
#: models.py:32
msgid "template"
msgstr "skabelon"
#: models.py:38
#: models.py:33
msgid "templates"
msgstr "skabeloner"

View file

@ -1,23 +1,18 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Jannis Leidel <jannis@leidel.info>, 2011.
#
msgid ""
msgstr ""
"Project-Id-Version: django-dbtemplates\n"
"Report-Msgid-Bugs-To: https://github.com/jezdez/django-dbtemplates/issues\n"
"POT-Creation-Date: 2011-08-15 13:13+0200\n"
"PO-Revision-Date: 2011-08-15 11:14+0000\n"
"Last-Translator: Jannis <jannis@leidel.info>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Project-Id-Version: 0.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-10-09 13:45+0200\n"
"PO-Revision-Date: 2008-08-19 17:11+0100\n"
"Last-Translator: Jannis Leidel <jannis@leidel.info>\n"
"Language-Team: Jannis Leidel <jannis@leidel.info>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: de\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"X-Poedit-Language: German\n"
#: admin.py:56
#: admin.py:29
msgid ""
"Leaving this empty causes Django to look for a template with the given name "
"and populate this field with its content."
@ -25,86 +20,60 @@ msgstr ""
"Wenn Sie dieses Feld leer lassen, wird Django versuchen, das Template mit "
"dem angegebenen Namen zu finden und mit dessen Inhalt das Feld zu füllen."
#: admin.py:82
msgid "Advanced"
msgstr "Erweiterte Einstellungen"
#: admin.py:85
#: admin.py:43
msgid "Date/time"
msgstr "Datum/Uhrzeit"
#: admin.py:102
#: admin.py:61
#, python-format
msgid "Cache of one template successfully invalidated."
msgid_plural "Cache of %(count)d templates successfully invalidated."
msgstr[0] "Der Cache eines Templates wurde erfolgreich geleert."
msgstr[1] "Der Cache von %(count)d Templates wurde erfolgreich geleert."
#: admin.py:106
#: admin.py:65
msgid "Invalidate cache of selected templates"
msgstr "Cache der ausgewählten Templates leeren"
#: admin.py:114
#: admin.py:74
#, python-format
msgid "Cache successfully repopulated with one template."
msgid_plural "Cache successfully repopulated with %(count)d templates."
msgstr[0] "Der Cache eines Templates wurde erfolgreich geleert und neu gefüllt."
msgstr[1] ""
"Der Cache von %(count)d Templates wurde erfolgreich geleert und neu gefüllt."
msgstr[1] "Der Cache von %(count)d Templates wurde erfolgreich geleert und neu gefüllt."
#: admin.py:118
#: admin.py:78
msgid "Repopulate cache with selected templates"
msgstr "Cache der ausgewählten Templates neu füllen"
#: admin.py:130
#, python-format
msgid "Template syntax check FAILED for %(names)s."
msgid_plural ""
"Template syntax check FAILED for %(count)d templates: %(names)s."
msgstr[0] "Template-Syntax von %(names)s ist FEHLERHAFT."
msgstr[1] "Template-Syntax von %(count)d Templates (%(names)s) ist FEHLERHAFT."
#: admin.py:138
#, python-format
msgid "Template syntax OK."
msgid_plural "Template syntax OK for %(count)d templates."
msgstr[0] "Template-Syntax ist OK."
msgstr[1] "Template-Syntax von %(count)d Templates ist OK."
#: admin.py:141
msgid "Check template syntax"
msgstr "Template-Syntax überprüfen"
#: admin.py:145 models.py:25
#: admin.py:82
msgid "sites"
msgstr "Seiten"
#: models.py:22
#: models.py:18
msgid "name"
msgstr "Name"
#: models.py:23
#: models.py:19
msgid "Example: 'flatpages/default.html'"
msgstr "Zum Beispiel: 'flatpages/default.html'"
#: models.py:24
#: models.py:20
msgid "content"
msgstr "Inhalt"
#: models.py:27
#: models.py:22
msgid "creation date"
msgstr "Erstellt"
#: models.py:29
#: models.py:24
msgid "last changed"
msgstr "Geändert"
#: models.py:37
#: models.py:32
msgid "template"
msgstr "Template"
#: models.py:38
#: models.py:33
msgid "templates"
msgstr "Templates"

View file

@ -8,97 +8,74 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-08-15 13:13+0200\n"
"POT-Creation-Date: 2009-10-09 13:45+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"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: admin.py:56
#: admin.py:29
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:82
msgid "Advanced"
msgstr ""
#: admin.py:85
#: admin.py:43
msgid "Date/time"
msgstr ""
#: admin.py:102
#: admin.py:61
#, python-format
msgid "Cache of one template successfully invalidated."
msgid_plural "Cache of %(count)d templates successfully invalidated."
msgstr[0] ""
msgstr[1] ""
#: admin.py:106
#: admin.py:65
msgid "Invalidate cache of selected templates"
msgstr ""
#: admin.py:114
#: admin.py:74
#, python-format
msgid "Cache successfully repopulated with one template."
msgid_plural "Cache successfully repopulated with %(count)d templates."
msgstr[0] ""
msgstr[1] ""
#: admin.py:118
#: admin.py:78
msgid "Repopulate cache with selected templates"
msgstr ""
#: admin.py:130
#, python-format
msgid "Template syntax check FAILED for %(names)s."
msgid_plural "Template syntax check FAILED for %(count)d templates: %(names)s."
msgstr[0] ""
msgstr[1] ""
#: admin.py:138
#, python-format
msgid "Template syntax OK."
msgid_plural "Template syntax OK for %(count)d templates."
msgstr[0] ""
msgstr[1] ""
#: admin.py:141
msgid "Check template syntax"
msgstr ""
#: admin.py:145 models.py:25
#: admin.py:82
msgid "sites"
msgstr ""
#: models.py:22
#: models.py:18
msgid "name"
msgstr ""
#: models.py:23
#: models.py:19
msgid "Example: 'flatpages/default.html'"
msgstr ""
#: models.py:24
#: models.py:20
msgid "content"
msgstr ""
#: models.py:27
#: models.py:22
msgid "creation date"
msgstr ""
#: models.py:29
#: models.py:24
msgid "last changed"
msgstr ""
#: models.py:37
#: models.py:32
msgid "template"
msgstr ""
#: models.py:38
#: models.py:33
msgid "templates"
msgstr ""

View file

@ -1,109 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Ville Säävuori <ville@syneus.fi>, 2011.
msgid ""
msgstr ""
"Project-Id-Version: django-dbtemplates\n"
"Report-Msgid-Bugs-To: https://github.com/jezdez/django-dbtemplates/issues\n"
"POT-Creation-Date: 2011-08-15 13:13+0200\n"
"PO-Revision-Date: 2011-08-15 11:14+0000\n"
"Last-Translator: Jannis <jannis@leidel.info>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: fi\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: admin.py:56
msgid ""
"Leaving this empty causes Django to look for a template with the given name "
"and populate this field with its content."
msgstr ""
"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:82
msgid "Advanced"
msgstr "Lisäasetukset"
#: admin.py:85
msgid "Date/time"
msgstr "Päiväys/aika"
#: admin.py:102
#, python-format
msgid "Cache of one template successfully invalidated."
msgid_plural "Cache of %(count)d templates successfully invalidated."
msgstr[0] "Yhden mallipohjan välimuisti on onnistuneesti tyhjennetty."
msgstr[1] "%(count)d mallipohjan välimusti on onnistuneesti tyhjennetty."
#: admin.py:106
msgid "Invalidate cache of selected templates"
msgstr "Tyhjennä valittujen mallipohjien välimuisti."
#: admin.py:114
#, python-format
msgid "Cache successfully repopulated with one template."
msgid_plural "Cache successfully repopulated with %(count)d templates."
msgstr[0] "Yhden mallipohjan välimuisti on täytetty onnistuneesti."
msgstr[1] "%(count)d mallipohjan välimuisti on täytetty onnistuneesti."
#: admin.py:118
msgid "Repopulate cache with selected templates"
msgstr "Täytä valittujen mallipohjien välimuisti."
#: admin.py:130
#, python-format
msgid "Template syntax check FAILED for %(names)s."
msgid_plural ""
"Template syntax check FAILED for %(count)d templates: %(names)s."
msgstr[0] ""
msgstr[1] ""
#: admin.py:138
#, python-format
msgid "Template syntax OK."
msgid_plural "Template syntax OK for %(count)d templates."
msgstr[0] ""
msgstr[1] ""
#: admin.py:141
msgid "Check template syntax"
msgstr ""
#: admin.py:145 models.py:25
msgid "sites"
msgstr "sivustot"
#: models.py:22
msgid "name"
msgstr "nimi"
#: models.py:23
msgid "Example: 'flatpages/default.html'"
msgstr "Esimerkiksi: 'flatpages/default.html'"
#: models.py:24
msgid "content"
msgstr "sisätö"
#: models.py:27
msgid "creation date"
msgstr "luontipäivä"
#: models.py:29
msgid "last changed"
msgstr "viimeksi muutettu"
#: models.py:37
msgid "template"
msgstr "mallipohja"
#: models.py:38
msgid "templates"
msgstr "mallipohjat"

View file

@ -1,108 +1,75 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Roland Frédéric <frederic.roland@creativeconvergence.be>, 2009.
#
#
msgid ""
msgstr ""
"Project-Id-Version: django-dbtemplates\n"
"Report-Msgid-Bugs-To: https://github.com/jezdez/django-dbtemplates/issues\n"
"POT-Creation-Date: 2011-08-15 13:13+0200\n"
"PO-Revision-Date: 2011-08-15 11:14+0000\n"
"Last-Translator: Jannis <jannis@leidel.info>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Project-Id-Version: Django DB Template 0.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-10-09 13:45+0200\n"
"PO-Revision-Date: 2009-10-21 19:16+0200\n"
"Last-Translator: David Paccoud <dpaccoud@gmail.com>\n"
"Language-Team: French\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: fr\n"
"Plural-Forms: nplurals=2; plural=(n > 1)\n"
"Content-Transfer-Encoding: 8bit"
#: admin.py:56
#: admin.py:29
msgid ""
"Leaving this empty causes Django to look for a template with the given name "
"and populate this field with its content."
msgstr ""
"Si vous laissez ceci vide , Django recherchera un modèle avec le nom donné "
"et remplira ce champ avec son contenu."
msgstr "Si vous laissez ceci vide , Django recherchera un modèle avec le nom donné et remplira ce champ avec son contenu."
#: admin.py:82
msgid "Advanced"
msgstr ""
#: admin.py:85
#: admin.py:43
msgid "Date/time"
msgstr "Date/heure"
#: admin.py:102
#, fuzzy, python-format
#: admin.py:61
#, python-format
msgid "Cache of one template successfully invalidated."
msgid_plural "Cache of %(count)d templates successfully invalidated."
msgstr[0] "Le cache d'un modèle a été invalidé avec succès."
msgstr[1] ""
msgstr "Le cache d'un modèle a été invalidé avec succès."
#: admin.py:106
#: admin.py:65
msgid "Invalidate cache of selected templates"
msgstr "Invalidation du cache des modèles sélectionnés"
#: admin.py:114
#, fuzzy, python-format
#: admin.py:74
#, python-format
msgid "Cache successfully repopulated with one template."
msgid_plural "Cache successfully repopulated with %(count)d templates."
msgstr[0] "Le cache d'un modèle a été rechargé avec succès."
msgstr[1] ""
msgstr "Le cache d'un modèle a été rechargé avec succès."
#: admin.py:118
#: admin.py:78
msgid "Repopulate cache with selected templates"
msgstr "Rechargement du cache des modèles sélectionnés"
#: admin.py:130
#, python-format
msgid "Template syntax check FAILED for %(names)s."
msgid_plural ""
"Template syntax check FAILED for %(count)d templates: %(names)s."
msgstr[0] ""
msgstr[1] ""
#: admin.py:138
#, python-format
msgid "Template syntax OK."
msgid_plural "Template syntax OK for %(count)d templates."
msgstr[0] ""
msgstr[1] ""
#: admin.py:141
msgid "Check template syntax"
msgstr ""
#: admin.py:145 models.py:25
#: admin.py:82
msgid "sites"
msgstr "sites"
#: models.py:22
#: models.py:18
msgid "name"
msgstr "nom"
#: models.py:23
#: models.py:19
msgid "Example: 'flatpages/default.html'"
msgstr "Exemple : 'flatpages/default.html'"
#: models.py:24
#: models.py:20
msgid "content"
msgstr "contenu"
#: models.py:27
#: models.py:22
msgid "creation date"
msgstr "date de création"
#: models.py:29
#: models.py:24
msgid "last changed"
msgstr "dernier changement"
#: models.py:37
#: models.py:32
msgid "template"
msgstr "modèle"
#: models.py:38
#: models.py:33
msgid "templates"
msgstr "modèles"

View file

@ -1,106 +1,82 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# translation of PACKAGE.
# Copyright (C) 2008 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# <>, 2008.
#
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: django-dbtemplates\n"
"Report-Msgid-Bugs-To: https://github.com/jezdez/django-dbtemplates/issues\n"
"POT-Creation-Date: 2011-08-15 13:13+0200\n"
"PO-Revision-Date: 2011-08-15 11:14+0000\n"
"Last-Translator: Jannis <jannis@leidel.info>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-10-09 13:45+0200\n"
"PO-Revision-Date: 2008-08-21 12:31+0300\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: he\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: admin.py:56
#: admin.py:29
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:82
msgid "Advanced"
msgstr ""
#: admin.py:85
#: admin.py:43
msgid "Date/time"
msgstr "תאריך / זמן"
#: admin.py:102
#: admin.py:61
#, python-format
msgid "Cache of one template successfully invalidated."
msgid_plural "Cache of %(count)d templates successfully invalidated."
msgstr[0] ""
msgstr[1] ""
#: admin.py:106
#: admin.py:65
msgid "Invalidate cache of selected templates"
msgstr ""
#: admin.py:114
#: admin.py:74
#, python-format
msgid "Cache successfully repopulated with one template."
msgid_plural "Cache successfully repopulated with %(count)d templates."
msgstr[0] ""
msgstr[1] ""
#: admin.py:118
#: admin.py:78
msgid "Repopulate cache with selected templates"
msgstr ""
#: admin.py:130
#, python-format
msgid "Template syntax check FAILED for %(names)s."
msgid_plural ""
"Template syntax check FAILED for %(count)d templates: %(names)s."
msgstr[0] ""
msgstr[1] ""
#: admin.py:138
#, python-format
msgid "Template syntax OK."
msgid_plural "Template syntax OK for %(count)d templates."
msgstr[0] ""
msgstr[1] ""
#: admin.py:141
msgid "Check template syntax"
msgstr ""
#: admin.py:145 models.py:25
#: admin.py:82
msgid "sites"
msgstr "אתרים"
#: models.py:22
#: models.py:18
msgid "name"
msgstr "שם"
#: models.py:23
#: models.py:19
msgid "Example: 'flatpages/default.html'"
msgstr "דוגמא: 'flatpages/default.html'"
#: models.py:24
#: models.py:20
msgid "content"
msgstr "תוכן"
#: models.py:27
#: models.py:22
msgid "creation date"
msgstr "נוצר ב"
#: models.py:29
#: models.py:24
msgid "last changed"
msgstr "שונה ב"
#: models.py:37
#: models.py:32
msgid "template"
msgstr "תבנית"
#: models.py:38
#: models.py:33
msgid "templates"
msgstr "תבניות"

View file

@ -1,22 +1,17 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
msgid ""
msgstr ""
"Project-Id-Version: django-dbtemplates\n"
"Report-Msgid-Bugs-To: https://github.com/jezdez/django-dbtemplates/issues\n"
"POT-Creation-Date: 2011-08-15 13:13+0200\n"
"PO-Revision-Date: 2011-08-15 11:14+0000\n"
"Last-Translator: Jannis <jannis@leidel.info>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Project-Id-Version: 0.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-10-09 13:45+0200\n"
"PO-Revision-Date: 2009-01-22 01:27+0100\n"
"Last-Translator: Marco Beri <marcoberi@gmail.com>\n"
"Language-Team: Jannis Leidel <jannis@leidel.info>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"X-Poedit-Language: German\n"
#: admin.py:56
#: admin.py:29
msgid ""
"Leaving this empty causes Django to look for a template with the given name "
"and populate this field with its content."
@ -24,85 +19,60 @@ msgstr ""
"Lasciandolo vuoto, Django cercherà un template con lo stesso nome che avete "
"indicato sopra e userà il suo contenuto per riempire questo campo."
#: admin.py:82
msgid "Advanced"
msgstr ""
#: admin.py:85
#: admin.py:43
msgid "Date/time"
msgstr ""
#: admin.py:102
#: admin.py:61
#, python-format
msgid "Cache of one template successfully invalidated."
msgid_plural "Cache of %(count)d templates successfully invalidated."
msgstr[0] ""
msgstr[1] ""
#: admin.py:106
#: admin.py:65
msgid "Invalidate cache of selected templates"
msgstr ""
#: admin.py:114
#: admin.py:74
#, python-format
msgid "Cache successfully repopulated with one template."
msgid_plural "Cache successfully repopulated with %(count)d templates."
msgstr[0] ""
msgstr[1] ""
#: admin.py:118
#: admin.py:78
msgid "Repopulate cache with selected templates"
msgstr ""
#: admin.py:130
#, python-format
msgid "Template syntax check FAILED for %(names)s."
msgid_plural ""
"Template syntax check FAILED for %(count)d templates: %(names)s."
msgstr[0] ""
msgstr[1] ""
#: admin.py:138
#, python-format
msgid "Template syntax OK."
msgid_plural "Template syntax OK for %(count)d templates."
msgstr[0] ""
msgstr[1] ""
#: admin.py:141
msgid "Check template syntax"
msgstr ""
#: admin.py:145 models.py:25
#: admin.py:82
msgid "sites"
msgstr ""
#: models.py:22
#: models.py:18
msgid "name"
msgstr "nome"
#: models.py:23
#: models.py:19
msgid "Example: 'flatpages/default.html'"
msgstr "Esempio: 'flatpages/default.html'"
#: models.py:24
#: models.py:20
msgid "content"
msgstr "contenuto"
#: models.py:27
#: models.py:22
msgid "creation date"
msgstr "data di creazione"
#: models.py:29
#: models.py:24
msgid "last changed"
msgstr "ultimo cambiamento"
#: models.py:37
#: models.py:32
msgid "template"
msgstr "template"
#: models.py:38
#: models.py:33
msgid "templates"
msgstr "template"

View file

@ -1,23 +1,17 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Herson Hersonls <hersonls@gmail.com>, 2011.
# Diego Búrigo Zacarão <diegobz@fedoraproject.org> 2009.
msgid ""
msgstr ""
"Project-Id-Version: django-dbtemplates\n"
"Report-Msgid-Bugs-To: https://github.com/jezdez/django-dbtemplates/issues\n"
"POT-Creation-Date: 2011-08-15 13:13+0200\n"
"PO-Revision-Date: 2011-08-15 11:14+0000\n"
"Last-Translator: Jannis <jannis@leidel.info>\n"
"Language-Team: Portuguese (Brazilian) (http://www.transifex.net/projects/p/django-dbtemplates/team/pt_BR/)\n"
"Project-Id-Version: 0.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-10-09 13:45+0200\n"
"PO-Revision-Date: 2008-08-31 11:45-0300\n"
"Last-Translator: Diego Búrigo Zacarão <diegobz@fedoraproject.org>\n"
"Language-Team: Brazilian Portuguese <fedora-trans-pt_br@redhat.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: pt_BR\n"
"Plural-Forms: nplurals=2; plural=(n > 1)\n"
#: admin.py:56
#: admin.py:29
msgid ""
"Leaving this empty causes Django to look for a template with the given name "
"and populate this field with its content."
@ -25,85 +19,60 @@ msgstr ""
"Manter isto vazio faz com que o Django procure por um modelo (template) com "
"o dado nome e preencha este campo com o seu conteúdo"
#: admin.py:82
msgid "Advanced"
msgstr "Avançado"
#: admin.py:85
#: admin.py:43
msgid "Date/time"
msgstr "Data/hora"
#: admin.py:102
#: admin.py:61
#, python-format
msgid "Cache of one template successfully invalidated."
msgid_plural "Cache of %(count)d templates successfully invalidated."
msgstr[0] ""
msgstr[1] ""
#: admin.py:106
#: admin.py:65
msgid "Invalidate cache of selected templates"
msgstr ""
#: admin.py:114
#: admin.py:74
#, python-format
msgid "Cache successfully repopulated with one template."
msgid_plural "Cache successfully repopulated with %(count)d templates."
msgstr[0] ""
msgstr[1] ""
#: admin.py:118
#: admin.py:78
msgid "Repopulate cache with selected templates"
msgstr ""
#: admin.py:130
#, python-format
msgid "Template syntax check FAILED for %(names)s."
msgid_plural ""
"Template syntax check FAILED for %(count)d templates: %(names)s."
msgstr[0] ""
msgstr[1] ""
#: admin.py:138
#, python-format
msgid "Template syntax OK."
msgid_plural "Template syntax OK for %(count)d templates."
msgstr[0] ""
msgstr[1] ""
#: admin.py:141
msgid "Check template syntax"
msgstr ""
#: admin.py:145 models.py:25
#: admin.py:82
msgid "sites"
msgstr "sites"
#: models.py:22
#: models.py:18
msgid "name"
msgstr "Name"
#: models.py:23
#: models.py:19
msgid "Example: 'flatpages/default.html'"
msgstr "Exemplo: 'flatpages/default.html'"
#: models.py:24
#: models.py:20
msgid "content"
msgstr "conteúdo"
#: models.py:27
#: models.py:22
msgid "creation date"
msgstr "Data de criação"
#: models.py:29
#: models.py:24
msgid "last changed"
msgstr "ultima modificação"
#: models.py:37
#: models.py:32
msgid "template"
msgstr "modelo"
#: models.py:38
#: models.py:33
msgid "templates"
msgstr "modelos"

View file

@ -1,106 +0,0 @@
# 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.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-07-30 14:03+0600\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"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\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"
#: admin.py:57
msgid ""
"Leaving this empty causes Django to look for a template with the given name "
"and populate this field with its content."
msgstr "Если вы оставите это поле незаполненным, Django будет искать шаблон с введённым именем и заполнит поле его содержимым."
#: admin.py:92
msgid "Advanced"
msgstr "Дополнительно"
#: admin.py:95
msgid "Date/time"
msgstr "Дата/время"
#: admin.py:112
#, python-format
msgid "Cache of one template successfully invalidated."
msgid_plural "Cache of %(count)d templates successfully invalidated."
msgstr[0] "Кэш для шаблона успешно очищен."
msgstr[1] "Кэш для шаблонов (%(count)d шт.) успешно очищен."
#: admin.py:116
msgid "Invalidate cache of selected templates"
msgstr "Очистить кэш для выделенных шаблонов"
#: admin.py:124
#, python-format
msgid "Cache successfully repopulated with one template."
msgid_plural "Cache successfully repopulated with %(count)d templates."
msgstr[0] "Кэш для шаблона успешно заполнен."
msgstr[1] "Кэш для шаблонов (%(count)d шт.) успешно заполнен."
#: admin.py:128
msgid "Repopulate cache with selected templates"
msgstr "Заполнить кэш для выделенных шаблонов"
#: admin.py:140
#, python-format
msgid "Template syntax check FAILED for %(names)s."
msgid_plural "Template syntax check FAILED for %(count)d templates: %(names)s."
msgstr[0] "Неверный синтаксис у шаблона %(names)s."
msgstr[1] "Неверный синтаксис у следующих шаблонов: %(names)s."
#: admin.py:148
#, python-format
msgid "Template syntax OK."
msgid_plural "Template syntax OK for %(count)d templates."
msgstr[0] "Синтаксис шаблона корректен."
msgstr[1] "Синтаксис шаблонов корректен."
#: admin.py:151
msgid "Check template syntax"
msgstr "Проверить синтаксис шаблона"
#: admin.py:155 models.py:29
msgid "sites"
msgstr "сайты"
#: models.py:26
msgid "name"
msgstr "название"
#: models.py:27
msgid "Example: 'flatpages/default.html'"
msgstr "Например: 'flatpages/default.html'"
#: models.py:28
msgid "content"
msgstr "содержимое"
#: models.py:31
msgid "creation date"
msgstr "дата создания"
#: models.py:33
msgid "last changed"
msgstr "последнее изменение"
#: models.py:41
msgid "template"
msgstr "шаблон"
#: models.py:42
msgid "templates"
msgstr "шаблоны"

View file

@ -1,102 +1,75 @@
# 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.
#
msgid ""
msgstr ""
"Project-Id-Version: django-dbtemplates\n"
"Report-Msgid-Bugs-To: https://github.com/jezdez/django-dbtemplates/issues\n"
"POT-Creation-Date: 2011-08-15 13:13+0200\n"
"PO-Revision-Date: 2011-08-15 11:14+0000\n"
"Last-Translator: Jannis <jannis@leidel.info>\n"
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-10-09 13:45+0200\n"
"PO-Revision-Date: 2010-01-05 17:23+0800\n"
"Last-Translator: 张昆 <zhangkun@web916.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: zh_CN\n"
"Plural-Forms: nplurals=1; plural=0\n"
#: admin.py:56
msgid ""
"Leaving this empty causes Django to look for a template with the given name "
"and populate this field with its content."
#: admin.py:29
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:82
msgid "Advanced"
msgstr ""
#: admin.py:85
#: admin.py:43
msgid "Date/time"
msgstr "日期/时间"
#: admin.py:102
#, fuzzy, python-format
#: admin.py:61
#, python-format
msgid "Cache of one template successfully invalidated."
msgid_plural "Cache of %(count)d templates successfully invalidated."
msgstr[0] "该模板的缓存已经成功撤销。"
msgstr "该模板的缓存已经成功撤销。"
#: admin.py:106
#: admin.py:65
msgid "Invalidate cache of selected templates"
msgstr "撤销选中模板的缓存"
#: admin.py:114
#, fuzzy, python-format
#: admin.py:74
#, python-format
msgid "Cache successfully repopulated with one template."
msgid_plural "Cache successfully repopulated with %(count)d templates."
msgstr[0] "该模板的缓存已经成功启用。"
msgstr "该模板的缓存已经成功启用。"
#: admin.py:118
#: admin.py:78
msgid "Repopulate cache with selected templates"
msgstr "重新启用选中模板的缓存"
#: admin.py:130
#, python-format
msgid "Template syntax check FAILED for %(names)s."
msgid_plural ""
"Template syntax check FAILED for %(count)d templates: %(names)s."
msgstr[0] ""
#: admin.py:138
#, python-format
msgid "Template syntax OK."
msgid_plural "Template syntax OK for %(count)d templates."
msgstr[0] ""
#: admin.py:141
msgid "Check template syntax"
msgstr ""
#: admin.py:145 models.py:25
#: admin.py:82
msgid "sites"
msgstr "站点"
#: models.py:22
#: models.py:18
msgid "name"
msgstr "名称"
#: models.py:23
#: models.py:19
msgid "Example: 'flatpages/default.html'"
msgstr "例如: 'flatpages/default.html'"
#: models.py:24
#: models.py:20
msgid "content"
msgstr "内容"
#: models.py:27
#: models.py:22
msgid "creation date"
msgstr "创建日期"
#: models.py:29
#: models.py:24
msgid "last changed"
msgstr "最新变更"
#: models.py:37
#: models.py:32
msgid "template"
msgstr "模板"
#: models.py:38
#: models.py:33
msgid "templates"
msgstr "模板"

View file

@ -1,19 +0,0 @@
from django.core.management.base import CommandError, BaseCommand
from dbtemplates.models import Template
from dbtemplates.utils.template import check_template_syntax
class Command(BaseCommand):
help = "Ensures templates stored in the database don't have syntax errors."
def handle(self, **options):
errors = []
for template in Template.objects.all():
valid, error = check_template_syntax(template)
if not valid:
errors.append(f'{template.name}: {error}')
if errors:
raise CommandError(
'Some templates contained errors\n%s' % '\n'.join(errors))
self.stdout.write('OK')

View file

@ -1,5 +1,6 @@
import sys
from django.core.management.base import CommandError, BaseCommand
from optparse import make_option
from django.core.management.base import CommandError, NoArgsCommand
from django.contrib.sites.models import Site
from dbtemplates.models import Template
@ -23,16 +24,13 @@ TEMPLATES = {
""",
}
class Command(BaseCommand):
help = "Creates the default error templates as database template objects."
def add_arguments(self, parser):
parser.add_argument(
"-f", "--force", action="store_true", dest="force",
default=False, help="overwrite existing database templates")
def handle(self, **options):
class Command(NoArgsCommand):
help = "Creates the 404.html and 500.html error templates as database template objects."
option_list = NoArgsCommand.option_list + (
make_option("-f", "--force", action="store_true", dest="force",
default=False, help="overwrite existing database templates"),
)
def handle_noargs(self, **options):
force = options.get('force')
try:
site = Site.objects.get_current()
@ -43,15 +41,13 @@ class Command(BaseCommand):
verbosity = int(options.get('verbosity', 1))
for error_code in (404, 500):
template, created = Template.objects.get_or_create(
name=f"{error_code}.html")
name="%s.html" % error_code)
if created or (not created and force):
template.content = TEMPLATES.get(error_code, '')
template.save()
template.sites.add(site)
if verbosity >= 1:
sys.stdout.write("Created database template "
"for %s errors.\n" % error_code)
self.stdout.write("Created database template for %s errors.\n" % error_code)
else:
if verbosity >= 1:
sys.stderr.write("A template for %s errors "
"already exists.\n" % error_code)
self.stderr.write("A template for %s errors already exists.\n" % error_code)

View file

@ -1,153 +1,76 @@
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.models import Template
from django.contrib.sites.models import Site
from django.core.management.base import BaseCommand, CommandError
from django.template.loader import _engine_list
from django.template.utils import get_app_template_dirs
ALWAYS_ASK, FILES_TO_DATABASE, DATABASE_TO_FILES = ("0", "1", "2")
DIRS = []
for engine in _engine_list():
DIRS.extend(engine.dirs)
DIRS = tuple(DIRS)
app_template_dirs = get_app_template_dirs("templates")
class Command(BaseCommand):
class Command(NoArgsCommand):
help = "Syncs file system templates with the database bidirectionally."
def add_arguments(self, parser):
parser.add_argument(
"-e",
"--ext",
dest="ext",
action="store",
default="html",
help="extension of the files you want to "
"sync with the database [default: %(default)s]",
)
parser.add_argument(
"-f",
"--force",
action="store_true",
dest="force",
default=False,
help="overwrite existing database templates",
)
parser.add_argument(
"-o",
"--overwrite",
action="store",
dest="overwrite",
default="0",
help="'0' - ask always, '1' - overwrite database "
"templates from template files, '2' - overwrite "
"template files from database templates",
)
parser.add_argument(
"-a",
"--app-first",
action="store_true",
dest="app_first",
default=False,
help="look for templates in applications "
"directories before project templates",
)
parser.add_argument(
"-d",
"--delete",
action="store_true",
dest="delete",
default=False,
help="Delete templates after syncing",
)
def handle(self, **options):
extension = options.get("ext")
force = options.get("force")
overwrite = options.get("overwrite")
app_first = options.get("app_first")
delete = options.get("delete")
option_list = NoArgsCommand.option_list + (
make_option("-e", "--ext", dest="ext", action="store", default="html",
help="extension of the files you want to sync with the database "
"[default: %default]"),
make_option("-f", "--force", action="store_true", dest="force",
default=False, help="overwrite existing database templates")
)
def handle_noargs(self, **options):
extension = options.get('ext')
force = options.get('force')
if not extension.startswith("."):
extension = f".{extension}"
extension = ".%s" % extension
try:
site = Site.objects.get_current()
except Exception:
raise CommandError(
"Please make sure to have the sites contrib "
"app installed and setup with a site object"
)
except:
raise CommandError("Please make sure to have the sites contrib "
"app installed and setup with a site object")
if app_first:
tpl_dirs = app_template_dirs + DIRS
else:
tpl_dirs = DIRS + app_template_dirs
templatedirs = [str(d) for d in tpl_dirs if os.path.isdir(d)]
if not type(settings.TEMPLATE_DIRS) in (tuple, list):
raise CommandError("Please make sure settings.TEMPLATE_DIRS is a "
"list or tuple.")
templatedirs = [d for d in
settings.TEMPLATE_DIRS + app_template_dirs if os.path.isdir(d)]
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(str(templatedir))[1]
if name.startswith("/"):
name = name[1:]
name = path.split(templatedir)[1][1:]
try:
t = Template.on_site.get(name__exact=name)
except Template.DoesNotExist:
if not force:
confirm = input(
"\nA '%s' template doesn't exist in the "
"database.\nCreate it with '%s'?"
" (y/[n]): "
"" % (name, path)
)
if force or confirm.lower().startswith("y"):
with open(path, encoding="utf-8") as f:
t = Template(name=name, content=f.read())
if force == False:
confirm = raw_input(
"\nA '%s' template doesn't exist in the database.\n"
"Create it with '%s'?"
" (y/[n]): """ % (name, path))
if confirm.lower().startswith('y') or force:
t = Template(name=name,
content=open(path, "r").read())
t.save()
t.sites.add(site)
else:
while True:
if overwrite == ALWAYS_ASK:
_i = (
"\n%(template)s exists in the database.\n"
"(1) Overwrite %(template)s with '%(path)s'\n" # noqa
"(2) Overwrite '%(path)s' with %(template)s\n" # noqa
"Type 1 or 2 or press <Enter> to skip: "
% {"template": t.__repr__(), "path": path}
)
confirm = input(_i)
else:
confirm = overwrite
if confirm in (
"",
FILES_TO_DATABASE,
DATABASE_TO_FILES,
):
if confirm == FILES_TO_DATABASE:
with open(path, encoding="utf-8") as f:
t.content = f.read()
t.save()
t.sites.add(site)
if delete:
try:
os.remove(path)
except OSError:
raise CommandError(
f"Couldn't delete {path}"
)
elif confirm == DATABASE_TO_FILES:
with open(path, "w", encoding="utf-8") as f: # noqa
f.write(t.content)
if delete:
t.delete()
while 1:
confirm = raw_input(
"\n%s exists in the database.\n"
"(1) Overwrite %s with '%s'\n"
"(2) Overwrite '%s' with %s\n"
"Type 1 or 2 or press <Enter> to skip: "
% (t.__repr__(),
t.__repr__(), path,
path, t.__repr__()))
if confirm == '' or confirm in ('1', '2'):
if confirm == '1':
t.content = open(path, 'r').read()
t.save()
t.sites.add(site)
elif confirm == '2':
open(path, 'w').write(t.content)
break

View file

@ -1,73 +0,0 @@
import django
import django.utils.timezone
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("sites", "0001_initial"),
]
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),
), # noqa
(
"creation_date",
models.DateTimeField(
default=django.utils.timezone.now,
verbose_name="creation date", # noqa
),
),
(
"last_changed",
models.DateTimeField(
default=django.utils.timezone.now,
verbose_name="last changed", # noqa
),
),
(
"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("sites"),
), # noqa
],
),
]

View file

@ -1,23 +0,0 @@
# Generated by Django 5.1 on 2025-05-26 19:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dbtemplates', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='template',
name='creation_date',
field=models.DateTimeField(auto_now_add=True, verbose_name='creation date'),
),
migrations.AlterField(
model_name='template',
name='last_changed',
field=models.DateTimeField(auto_now=True, verbose_name='last changed'),
),
]

View file

@ -1,16 +1,17 @@
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
# -*- coding: utf-8 -*-
from datetime import datetime
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 gettext_lazy as _
from django.template import TemplateDoesNotExist
from django.template.loader import find_template_source
from django.core.exceptions import ImproperlyConfigured
from django.contrib.sites.models import Site
from django.contrib.sites.managers import CurrentSiteManager
from dbtemplates import settings
class Template(models.Model):
@ -18,15 +19,14 @@ 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.
"""
id = models.AutoField(primary_key=True, verbose_name=_('ID'),
serialize=False, auto_created=True)
name = models.CharField(_('name'), max_length=100,
name = models.CharField(_('name'), unique=True, max_length=100,
help_text=_("Example: 'flatpages/default.html'"))
content = models.TextField(_('content'), blank=True)
sites = models.ManyToManyField(Site, verbose_name=_('sites'),
blank=True)
creation_date = models.DateTimeField(_('creation date'), auto_now_add=True)
last_changed = models.DateTimeField(_('last changed'), auto_now=True)
sites = models.ManyToManyField(Site)
creation_date = models.DateTimeField(_('creation date'),
default=datetime.now)
last_changed = models.DateTimeField(_('last changed'),
default=datetime.now)
objects = models.Manager()
on_site = CurrentSiteManager('sites')
@ -37,44 +37,72 @@ class Template(models.Model):
verbose_name_plural = _('templates')
ordering = ('name',)
def __str__(self):
def __unicode__(self):
return self.name
def populate(self, name=None):
"""
Tries to find a template with the same name and populates
the content field if found.
"""
if name is None:
name = self.name
try:
source = get_template_source(name)
if source:
self.content = source
except TemplateDoesNotExist:
pass
def save(self, *args, **kwargs):
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.DBTEMPLATES_AUTO_POPULATE_CONTENT and not self.content:
self.populate()
super().save(*args, **kwargs)
if not self.content:
try:
source, origin = find_template_source(self.name)
if source:
self.content = source
except TemplateDoesNotExist:
pass
super(Template, self).save(*args, **kwargs)
def get_cache_backend():
path = settings.CACHE_BACKEND
if path:
i = path.rfind('.')
module, attr = path[:i], path[i+1:]
try:
mod = __import__(module, {}, {}, [attr])
except ImportError, e:
raise ImproperlyConfigured(
'Error importing dbtemplates cache backend %s: "%s"' %
(module, e))
try:
cls = getattr(mod, attr)
except AttributeError:
raise ImproperlyConfigured(
'Module "%s" does not define a "%s" cache backend' %
(module, attr))
return cls()
return False
backend = 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.
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)
if settings.ADD_DEFAULT_SITE:
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)
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)
backend.save(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.
"""
backend.remove(instance.name)
if backend:
signals.post_save.connect(add_template_to_cache, sender=Template)
signals.pre_delete.connect(remove_cached_template, sender=Template)

17
dbtemplates/settings.py Normal file
View file

@ -0,0 +1,17 @@
import os
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
CACHE_BACKEND = getattr(settings, 'DBTEMPLATES_CACHE_BACKEND', None)
ADD_DEFAULT_SITE = getattr(settings, 'DBTEMPLATES_ADD_DEFAULT_SITE', True)
MEDIA_PREFIX = getattr(settings, 'DBTEMPLATES_MEDIA_PREFIX',
os.path.join(settings.MEDIA_ROOT, '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)

View file

@ -1,175 +0,0 @@
import os
import shutil
import tempfile
from unittest import mock
from django.conf import settings as django_settings
from django.core.cache.backends.base import BaseCache
from django.core.management import call_command
from django.template import loader, TemplateDoesNotExist
from django.test import TestCase
from django.contrib.sites.models import Site
from dbtemplates.conf import settings
from dbtemplates.models import Template
from dbtemplates.utils.cache import get_cache_backend, get_cache_key
from dbtemplates.utils.template import (get_template_source,
check_template_syntax)
from dbtemplates.management.commands.sync_templates import (FILES_TO_DATABASE,
DATABASE_TO_FILES)
class DbTemplatesTestCase(TestCase):
def setUp(self):
self.old_TEMPLATES = settings.TEMPLATES
if 'dbtemplates.loader.Loader' not in settings.TEMPLATES:
loader.template_source_loaders = None
settings.TEMPLATES = list(settings.TEMPLATES) + [
'dbtemplates.loader.Loader'
]
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 tearDown(self):
loader.template_source_loaders = None
settings.TEMPLATES = self.old_TEMPLATES
def test_basics(self):
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])
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_sites(self):
old_add_default_site = settings.DBTEMPLATES_ADD_DEFAULT_SITE
old_site_id = django_settings.SITE_ID
try:
settings.DBTEMPLATES_ADD_DEFAULT_SITE = False
t_site1 = Template.objects.create(
name='copyright.html', content='(c) example.com')
t_site1.sites.add(self.site1)
t_site2 = Template.objects.create(
name='copyright.html', content='(c) example.org')
t_site2.sites.add(self.site2)
django_settings.SITE_ID = Site.objects.create(
domain="example.net", name="example.net").id
Site.objects.clear_cache()
self.assertRaises(TemplateDoesNotExist,
loader.get_template, "copyright.html")
finally:
django_settings.SITE_ID = old_site_id
settings.DBTEMPLATES_ADD_DEFAULT_SITE = old_add_default_site
def test_load_templates(self):
result = loader.get_template("base.html").render()
self.assertEqual(result, 'base')
result2 = loader.get_template("sub.html").render()
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()))
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.TEMPLATES[0].get('DIRS', [])
temp_template_dir = tempfile.mkdtemp('dbtemplates')
temp_template_path = os.path.join(temp_template_dir, 'temp_test.html')
temp_template = open(temp_template_path, 'w', encoding='utf-8')
try:
temp_template.write('temp test')
settings.TEMPLATES[0]['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.TEMPLATES[0]['DIRS']
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.assertEqual('temp test modified',
open(temp_template_path,
encoding='utf-8').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.TEMPLATES[0]['DIRS'] = old_template_dirs
shutil.rmtree(temp_template_dir)
def test_get_cache(self):
self.assertTrue(isinstance(get_cache_backend(), BaseCache))
def test_check_template_syntax(self):
bad_template, _ = Template.objects.get_or_create(
name='bad.html', content='{% if foo %}Bar')
good_template, _ = Template.objects.get_or_create(
name='good.html', content='{% if foo %}Bar{% endif %}')
self.assertFalse(check_template_syntax(bad_template)[0])
self.assertTrue(check_template_syntax(good_template)[0])
def test_get_cache_name(self):
self.assertEqual(get_cache_key('name with spaces'),
'dbtemplates::name-with-spaces::1')
def test_cache_invalidation(self):
# Add t1 into the cache of site2
self.t1.sites.add(self.site2)
with mock.patch('django.contrib.sites.models.SiteManager.get_current',
return_value=self.site2):
result = loader.get_template("base.html").render()
self.assertEqual(result, 'base')
# Update content
self.t1.content = 'new content'
self.t1.save()
result = loader.get_template("base.html").render()
self.assertEqual(result, 'new content')
# Cache invalidation should work across sites.
# Site2 should see the new content.
with mock.patch('django.contrib.sites.models.SiteManager.get_current',
return_value=self.site2):
result = loader.get_template("base.html").render()
self.assertEqual(result, 'new content')

View file

@ -1,51 +0,0 @@
DBTEMPLATES_CACHE_BACKEND = 'dummy://'
DATABASE_ENGINE = 'sqlite3'
# SQLite does not support removing unique constraints (see #28)
SOUTH_TESTS_MIGRATE = False
SITE_ID = 1
SECRET_KEY = 'something-something'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:',
}
}
INSTALLED_APPS = [
'django.contrib.contenttypes',
'django.contrib.sites',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.admin',
'django.contrib.auth',
'dbtemplates',
]
MIDDLEWARE = (
'django.contrib.sessions.middleware.SessionMiddleware',
'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',
)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'OPTIONS': {
'loaders': TEMPLATE_LOADERS,
'context_processors': [
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
]
}
},
]

63
dbtemplates/tests.py Normal file
View file

@ -0,0 +1,63 @@
from django import VERSION
from django.test import TestCase
from django.contrib.sites.models import Site
from django.template import loader, Context
from django.core.management import call_command
from dbtemplates import settings
from dbtemplates.loader import load_template_source
from dbtemplates.models import Template
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")
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)
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_load_templates(self):
self.test_basiscs()
loader.template_source_loaders = [load_template_source]
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>')
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
def test_automatic_sync(self):
admin_base_template, origin = loader.find_template_source('admin/base.html')
template = Template.objects.create(name='admin/base.html')
self.assertEqual(admin_base_template, template.content)

View file

@ -1,62 +0,0 @@
from dbtemplates.conf import settings
from django.contrib.sites.models import Site
from django.core import signals
from django.template.defaultfilters import slugify
def get_cache_backend():
"""
Compatibilty wrapper for getting Django's cache backend instance
"""
from django.core.cache import caches
cache = caches.create_connection(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()
def get_cache_key(name, site=None):
if site is None:
site = Site.objects.get_current()
return f"dbtemplates::{slugify(name)}::{site.pk}"
def get_cache_notfound_key(name):
return get_cache_key(name) + "::notfound"
def remove_notfound_key(instance):
# Remove notfound key as soon as we save the template.
cache.delete(get_cache_notfound_key(instance.name))
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)
remove_notfound_key(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.
"""
for site in instance.sites.all():
cache.delete(get_cache_key(instance.name, site=site))

View file

@ -1,33 +0,0 @@
from django.template import (Template, TemplateDoesNotExist,
TemplateSyntaxError)
def get_loaders():
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):
source = None
for loader in get_loaders():
if loader.__module__.startswith('dbtemplates.'):
# Don't give a damn about dbtemplates' own loader.
continue
for origin in loader.get_template_sources(name):
try:
source = loader.get_contents(origin)
except (NotImplementedError, TemplateDoesNotExist):
continue
if source:
return source
def check_template_syntax(template):
try:
Template(template.content)
except TemplateSyntaxError as e:
return (False, e)
return (True, None)

View file

@ -1,130 +0,0 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/asd.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/asd.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/asd"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/asd"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
make -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

230
docs/_theme/nature/static/nature.css_t vendored Normal file
View file

@ -0,0 +1,230 @@
/**
* Sphinx stylesheet -- default theme
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
@import url("basic.css");
/* -- page layout ----------------------------------------------------------- */
body {
font-family: Arial, sans-serif;
font-size: 100%;
background-color: #111;
color: #555;
margin: 0;
padding: 0;
}
div.documentwrapper {
float: left;
width: 100%;
}
div.bodywrapper {
margin: 0 0 0 300px;
}
hr{
border: 1px solid #B1B4B6;
}
div.document {
background-color: #eee;
}
div.body {
background-color: #ffffff;
color: #3E4349;
padding: 0 30px 30px 30px;
font-size: 0.8em;
}
div.footer {
color: #555;
width: 100%;
padding: 13px 0;
text-align: center;
font-size: 75%;
}
div.footer a {
color: #444;
text-decoration: underline;
}
div.related {
background-color: #6BA81E;
line-height: 32px;
color: #fff;
text-shadow: 0px 1px 0 #444;
font-size: 0.80em;
}
div.related a {
color: #E2F3CC;
}
div.sphinxsidebar {
font-size: 0.75em;
line-height: 1.5em;
width: 300px
}
div.sphinxsidebarwrapper{
padding: 20px 0;
}
div.sphinxsidebar h3,
div.sphinxsidebar h4 {
font-family: Arial, sans-serif;
color: #222;
font-size: 1.2em;
font-weight: normal;
margin: 0;
padding: 5px 10px;
background-color: #ddd;
text-shadow: 1px 1px 0 white
}
div.sphinxsidebar h4{
font-size: 1.1em;
}
div.sphinxsidebar h3 a {
color: #444;
}
div.sphinxsidebar p {
color: #888;
padding: 5px 20px;
}
div.sphinxsidebar p.topless {
}
div.sphinxsidebar ul {
margin: 10px 10px 10px 20px;
padding: 0;
color: #000;
}
div.sphinxsidebar a {
color: #444;
}
div.sphinxsidebar input {
border: 1px solid #ccc;
font-family: sans-serif;
font-size: 1em;
}
div.sphinxsidebar input[type=text]{
margin-left: 20px;
}
/* -- body styles ----------------------------------------------------------- */
a {
color: #005B81;
text-decoration: none;
}
a:hover {
color: #E32E00;
text-decoration: underline;
}
div.body h1,
div.body h2,
div.body h3,
div.body h4,
div.body h5,
div.body h6 {
font-family: Arial, sans-serif;
background-color: #BED4EB;
font-weight: normal;
color: #212224;
margin: 30px 0px 10px 0px;
padding: 5px 0 5px 10px;
text-shadow: 0px 1px 0 white
}
div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; }
div.body h2 { font-size: 150%; background-color: #C8D5E3; }
div.body h3 { font-size: 120%; background-color: #D8DEE3; }
div.body h4 { font-size: 110%; background-color: #D8DEE3; }
div.body h5 { font-size: 100%; background-color: #D8DEE3; }
div.body h6 { font-size: 100%; background-color: #D8DEE3; }
a.headerlink {
color: #c60f0f;
font-size: 0.8em;
padding: 0 4px 0 4px;
text-decoration: none;
}
a.headerlink:hover {
background-color: #c60f0f;
color: white;
}
div.body p, div.body dd, div.body li {
line-height: 1.5em;
}
div.admonition p.admonition-title + p {
display: inline;
}
div.highlight{
background-color: white;
}
div.note {
background-color: #eee;
border: 1px solid #ccc;
}
div.seealso {
background-color: #ffc;
border: 1px solid #ff6;
}
div.topic {
background-color: #eee;
}
div.warning {
background-color: #ffe4e4;
border: 1px solid #f66;
}
p.admonition-title {
display: inline;
}
p.admonition-title:after {
content: ":";
}
pre {
padding: 10px;
background-color: White;
color: #222;
line-height: 1.2em;
border: 1px solid #C6C9CB;
font-size: 1.2em;
margin: 1.5em 0 1.5em 0;
-webkit-box-shadow: 1px 1px 1px #d8d8d8;
-moz-box-shadow: 1px 1px 1px #d8d8d8;
}
tt {
background-color: #ecf0f3;
color: #222;
padding: 1px 2px;
font-size: 1.2em;
font-family: monospace;
}

54
docs/_theme/nature/static/pygments.css vendored Normal file
View file

@ -0,0 +1,54 @@
.c { color: #999988; font-style: italic } /* Comment */
.k { font-weight: bold } /* Keyword */
.o { font-weight: bold } /* Operator */
.cm { color: #999988; font-style: italic } /* Comment.Multiline */
.cp { color: #999999; font-weight: bold } /* Comment.preproc */
.c1 { color: #999988; font-style: italic } /* Comment.Single */
.gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.ge { font-style: italic } /* Generic.Emph */
.gr { color: #aa0000 } /* Generic.Error */
.gh { color: #999999 } /* Generic.Heading */
.gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.go { color: #111 } /* Generic.Output */
.gp { color: #555555 } /* Generic.Prompt */
.gs { font-weight: bold } /* Generic.Strong */
.gu { color: #aaaaaa } /* Generic.Subheading */
.gt { color: #aa0000 } /* Generic.Traceback */
.kc { font-weight: bold } /* Keyword.Constant */
.kd { font-weight: bold } /* Keyword.Declaration */
.kp { font-weight: bold } /* Keyword.Pseudo */
.kr { font-weight: bold } /* Keyword.Reserved */
.kt { color: #445588; font-weight: bold } /* Keyword.Type */
.m { color: #009999 } /* Literal.Number */
.s { color: #bb8844 } /* Literal.String */
.na { color: #008080 } /* Name.Attribute */
.nb { color: #999999 } /* Name.Builtin */
.nc { color: #445588; font-weight: bold } /* Name.Class */
.no { color: #ff99ff } /* Name.Constant */
.ni { color: #800080 } /* Name.Entity */
.ne { color: #990000; font-weight: bold } /* Name.Exception */
.nf { color: #990000; font-weight: bold } /* Name.Function */
.nn { color: #555555 } /* Name.Namespace */
.nt { color: #000080 } /* Name.Tag */
.nv { color: purple } /* Name.Variable */
.ow { font-weight: bold } /* Operator.Word */
.mf { color: #009999 } /* Literal.Number.Float */
.mh { color: #009999 } /* Literal.Number.Hex */
.mi { color: #009999 } /* Literal.Number.Integer */
.mo { color: #009999 } /* Literal.Number.Oct */
.sb { color: #bb8844 } /* Literal.String.Backtick */
.sc { color: #bb8844 } /* Literal.String.Char */
.sd { color: #bb8844 } /* Literal.String.Doc */
.s2 { color: #bb8844 } /* Literal.String.Double */
.se { color: #bb8844 } /* Literal.String.Escape */
.sh { color: #bb8844 } /* Literal.String.Heredoc */
.si { color: #bb8844 } /* Literal.String.Interpol */
.sx { color: #bb8844 } /* Literal.String.Other */
.sr { color: #808000 } /* Literal.String.Regex */
.s1 { color: #bb8844 } /* Literal.String.Single */
.ss { color: #bb8844 } /* Literal.String.Symbol */
.bp { color: #999999 } /* Name.Builtin.Pseudo */
.vc { color: #ff99ff } /* Name.Variable.Class */
.vg { color: #ff99ff } /* Name.Variable.Global */
.vi { color: #ff99ff } /* Name.Variable.Instance */
.il { color: #009999 } /* Literal.Number.Integer.Long */

4
docs/_theme/nature/theme.conf vendored Normal file
View file

@ -0,0 +1,4 @@
[theme]
inherit = basic
stylesheet = nature.css
pygments_style = tango

View file

@ -1,125 +0,0 @@
=================
Advanced features
=================
.. _caching:
Caching
=======
``dbtemplates`` uses Django's default caching infrastructure for caching, and
operates automatically when creating, updating or deleting templates in
the database.
To enable one of them you need to specify a setting called
``DBTEMPLATES_CACHE_BACKEND`` to one of the valid values Django's
``CACHE_BACKEND`` can be set to. E.g.::
DBTEMPLATES_CACHE_BACKEND = 'memcached://127.0.0.1:11211/'
.. note::
Starting in version 1.0 ``dbtemplates`` allows you also to set the new
dict-based ``CACHES`` setting, which was introduced in Django 1.3.
All you have to do is to provide a new entry in the ``CACHES`` dict
named ``'dbtemplates'``, e.g.::
CACHES = {
'dbtemplates': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
Please see the `cache documentation`_ if you want to know more about it.
.. _cache documentation: http://docs.djangoproject.com/en/dev/topics/cache/#setting-up-the-cache
.. _versioned:
Versioned storage
=================
``dbtemplates`` comes prepared to use the third party Django app
`django-reversion`_, that once installed besides ``dbtemplates`` allows you
to jump back to old versions of your templates. It automatically saves every
state when you save the template in your database and provides an easy to use
interface.
Please refer to `django-reversion's documentation`_ for more information
about how it works.
.. hint::
Just visit the "History" section of each template instance and browse its history.
Short installation howto
------------------------
1. Get the source from the `django-reversion`_ project site and put it
somewhere on your `PYTHONPATH`.
2. Add ``reversion`` to the ``INSTALLED_APPS`` setting of your Django project
3. Sync your database with ``python manage.py syncdb``
4. Set ``DBTEMPLATES_USE_REVERSION`` setting to ``True``
History compare view
--------------------
You can also use ``dbtemplates`` together with `django-reversion-compare`_ which
provides a history compare view to compare two versions of a model which is under
reversion.
.. _django-reversion: https://github.com/etianen/django-reversion
.. _django-reversion's documentation: https://django-reversion.readthedocs.io/en/latest/
.. _django-reversion-compare: https://github.com/jedie/django-reversion-compare
.. _commands:
Management commands
===================
``dbtemplates`` comes with two `Django management commands`_ to be used with
``django-admin.py`` or ``manage.py``:
* ``sync_templates``
Enables you to sync your already existing file systems templates with the
database. It will guide you through the whole process.
* ``create_error_templates``
Tries to add the two templates ``404.html`` and ``500.html`` that are used
by Django when a error occurs.
* ``check_template_syntax``
.. versionadded:: 1.2
Checks the saved templates whether they are valid Django templates.
.. _Django management commands: http://docs.djangoproject.com/en/dev/ref/django-admin/
.. _admin_actions:
Admin actions
=============
``dbtemplates`` provides two `admin actions`_ to be used with Django>=1.1.
* ``invalidate_cache``
Invalidates the cache of the selected templates by calling the appropriate
cache backend methods.
* ``repopulate_cache``
Repopulates the cache with selected templates by invalidating it first and
filling then after that.
* ``check_syntax``
.. versionadded:: 1.2
Checks the selected tempaltes for syntax errors.
.. _admin actions: http://docs.djangoproject.com/en/dev/ref/contrib/admin/actions/

View file

@ -1,428 +0,0 @@
Changelog
=========
v5.0 (unreleased)
-----------------
.. warning::
This is a backwards-incompatible release!
* Dropped support for Python 3.7 and Django < 4.2.
* Added support for Python 3.11, 3.12, 3.13.
* Django 5.x support
v4.0 (2022-09-3)
-----------------
.. warning::
This is a backwards-incompatible release!
* Dropped support for Python 2.7 and Django < 3.2.
* Added support for Python 3.8, 3.9, 3.10.
* Moved test runner to GitHub Actions:
http://github.com/jazzband/django-dbtemplates/actions
* Django 4.x support
v3.0 (2019-01-27)
-----------------
.. warning::
This is a backwards-incompatible release!
* Dropped support for Django < 1.11.
* Added support for Django 2.0 and 2.1.
* Added support for Python 3.7.
* Recompiled Russian locale.
* Fixed byte string in migration file that caused the migration
system to falsely think that there are new changes.
* Fixed string representation of template model, e.g. to improve
readability in choice fields.
v2.0 (2016-09-29)
-----------------
.. warning::
This is a backwards-incompatible release!
* Moved maintenance to the `Jazzband <https://jazzband.co/>`_
* Dropped support for Python 2.6
* Added support for Python 3.4 and 3.5
* Dropped support for Django < 1.8
* Removed South migrations. Please use Django's native migration system instead
* Removed the example project since it's out-of-date quickly
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)
-------------------
* Minor release to move away from nose again and use own
`django-discover-runner`_.
.. _`django-discover-runner`: http://pypi.python.org/pypi/django-discover-runner
v1.3 (2012-05-07)
-----------------
* Dropped support for Django < 1.3 **backwards incompatible**
* Dropped using versiontools in favor of home made solution.
* Added optional support for TinyMCE editor instead of the CodeMirror
editor (just enable ``DBTEMPLATES_USE_TINYMCE``).
* Fixed compatibility to Django 1.4's handling of the ``DATABASES``
setting. Should also respect database routers now.
* Fixed an issue of the cache key generation in combination with
memcache's inability to stomach spaces.
* Moved test runner to use nose_ and a hosted CI project at Travis_:
http://travis-ci.org/jazzband/django-dbtemplates
.. _nose: https://nose.readthedocs.io/
.. _Travis: http://travis-ci.org
v1.2.1 (2011-09-07)
-------------------
* Fixed a wrong use of the non-lazy localization tools.
* Fixed bugs in the documentation.
* Make use of django-appconf and versiontools.
v1.2 (2011-08-15)
-----------------
* Refactored the template loader to be even more cache effective.
* Added ``check_template_syntax`` management command and admin action
to make sure the saved templates are valid Django templates.
v1.1.1 (2011-07-08)
-------------------
* Fixed bug in cache loading (again).
* Fixed bugs in the documentation.
.. note::
Since ``dbtemplates`` removed support for Django lower than 1.2 you
have to use the template loader class in the ``TEMPLATE_LOADERS``
(``'dbtemplates.loader.Loader'``) and **not** the previosly included
function that ended with ``load_template_source``.
v1.1 (2011-07-06)
-----------------
* **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.
v1.0.1 (2011-04-14)
-------------------
* Minor bugfixes with regard to the new cache handling.
v1.0 (2011-04-11)
-----------------
.. warning::
This is the first stable release of django-dbtemplates which comes with a
series of backwards incompatible changes.
* Removed own caching mechanism in favor of Django based caching mechanism.
The ``DBTEMPLATES_CACHE_BACKEND`` is expected to be a valid cache backend
URI, just like Django's own ``CACHE_BACKEND`` setting. In Django >= 1.3
an ``'dbtemplates'`` entry in the ``CACHES`` setting is also considered
valid.
* Added tox configuration to test ``dbtemplates`` on Python 2.5, 2.6 and 2.7
with Django 1.1.X, 1.2.X and 1.3.X.
* Added Transifex configuration.
* Use ``STATIC_URL`` setting instead of ``MEDIA_URL`` for the media prefix.
Also moved files from media/* to static/* to follow convention introduced
in Django 1.3.
* Use ReadTheDocs for documentation hosting.
v0.8.0 (2010-11-07)
-------------------
* Added Finnish translation (by jholster)
* Added --overwrite and --app-first options to sync_templates command (by Alex Kamedov).
v0.7.4 (2010-09-23)
-------------------
* Fixed tests.
v0.7.3 (2010-09-21)
-------------------
* Added ``DBTEMPLATES_AUTO_POPULATE_CONTENT`` setting to be able to disable
to auto-populating of template content.
* Fixed cosmetic issue in admin with collapsable fields.
v0.7.2 (2010-09-04)
-------------------
* Moved to Github again. Sigh.
v0.7.1 (2010-07-07)
-------------------
* Fixed problem with the CodeMirror textarea, which wasn't completely
disabled before.
* Fixed problem with the ``DBTEMPLATES_MEDIA_PREFIX`` setting, which defaults
now to ``os.path.join(settings.MEDIA_ROOT, 'dbtemplates')`` now.
In other words, if you don't specify a ``DBTEMPLATES_MEDIA_PREFIX`` setting
and have the CodeMirror textarea enabled, dbtemplates will look in a
subdirectory of your site's ``MEDIA_ROOT`` for the CodeMirror media files.
v0.7.0 (2010-06-24)
-------------------
* Added CodeMirror_-based syntax highlighting textarea, based on the amaxing
work_ by `Nic Pottier`_. Set the ``DBTEMPLATES_USE_CODEMIRROR`` setting
to ``True`` to enable it.
* Make use of the full width in plain textarea mode.
* Added Chinese translation
* Added support for Django 1.2
* Updated French translation
* Added ``DBTEMPLATES_USE_REVERSION`` setting to be able to explicitely enable
reversion support. (Default: ``False``)
.. _CodeMirror: http://marijn.haverbeke.nl/codemirror/
.. _work: https://gist.github.com/368758/86bcafe53c438e2e2a0e3442c3b30f2c6011fbba
.. _`Nic Pottier`: http://github.com/nicpottier
v0.6.1 (2009-10-19)
-------------------
* Fixed issue with default site of a template, added ability to disable
default site (``DBTEMPLATES_ADD_DEFAULT_SITE``).
v0.6.0 (2009-10-09)
-------------------
* Updated and added locales (Danish, Brazilian Portuguese)
* Fixes an ambiguity problem with the cache invalidation
* Added ``invalidate_cache`` and ``repopulate_cache`` admin actions
* Added Sphinx documentation
v0.5.7
------
* Updates to the docs
* switch back to Bitbucket
* fixed tests
* Added Italian translation
* list of sites the template is used on
* fixed bug in ``create_error_template`` command.
v0.5.4
------
* Made loader and cache backends site-aware.
* The filesystem cache backend now saves the files under
``<dir>/<site_domain>/<file_name>``.
* The Django cache backend the Site id in the cache key
* Template is now saved explicitly to backend if not existent in cache
(e.g. if deleted manually or invalidated).
v0.5.3
------
* Removed automatic creation of 404.html and 50v0.html templates and added a
new management command for those cases called ``create_error_templates``
* Also reverted move to Bitbucket
v0.5.2
------
* Fixed a problem with ``django.contrib.sites`` when its table hasn't been
populated yet on initialization of dbtemplates. Thanks for the report,
Kevin Fricovsky
* Added an example Django project and docs for it
v0.5.1
------
* Removed unneeded code that registered the model with reversion.
* Updated docs a bit.
* Moved codebase to Bitbucket.
* Removed legacy ``sync_templates.py`` script, use ``django-admin.py
sync_templates`` from now on.
v0.5.0
------
* Added support for `django-reversion`_
* added feature that populates the content field automatically when left
empty by using Django's other template loaders
* added caching backend system with two default backends:
* ``FileSystemBackend``
* ``DjangoCacheBackend``
More about it in the `blog post`_ and in the docs.
.. _django-reversion: http://code.google.com/p/django-reversion/
.. _blog post: http://jannisleidel.com/2008/11/updates-to-django-dbtemplates-and-half-assed-promise/
v0.4.7
------
* Minor bugfix
v0.4.6
------
* Minor doc change and PyPI support
v0.4.5
------
* fixed the --force option of the sync_templates command
v0.4.4
------
* fixed error in custom model save() after changes in Django `r8670`_.
.. _r8670: http://code.djangoproject.com/changeset/8670
v0.4.3
------
* removed oldforms code
v0.4.2
------
* added Hebrew translation (by mkriheli)
v0.4.1
------
* added French (by Roland Frederic) and German locale
v0.4.0
------
* adds better support for newforms-admin
* don't forget to load the dbtemplates.admin, e.g. by using
django.contrib.admin.autodiscover() in you urls.py
v0.3.1
------
* adds a new management command *sync_templates* for bidirectional syncing
between filesystem and database (backwards-compatible) and
FilesystemCaching (thanks, Arne Brodowski!)
v0.2.5
------
* adds support for newforms-admin
Support
=======
Please leave your questions and messages on the designated site:
http://github.com/jazzband/django-dbtemplates/issues/

View file

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
#
# django-dbtemplates documentation build configuration file, created by
# sphinx-quickstart on Fri Oct 9 14:52:11 2009.
@ -15,7 +16,7 @@ import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.append(os.path.abspath('.'))
#sys.path.append(os.path.abspath('.'))
# -- General configuration -----------------------------------------------------
@ -36,22 +37,17 @@ source_suffix = '.txt'
master_doc = 'index'
# General information about the project.
project = 'django-dbtemplates'
copyright = '2007-2019, Jannis Leidel and contributors'
project = u'django-dbtemplates'
copyright = u'2010, 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.
try:
from dbtemplates import __version__
# The short X.Y version.
version = '.'.join(__version__.split('.')[:2])
# The full version, including alpha/beta/rc tags.
release = __version__
except ImportError:
version = release = 'dev'
version = '0.7.2'
# The full version, including alpha/beta/rc tags.
release = '0.7.2'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@ -95,7 +91,7 @@ pygments_style = 'sphinx'
# The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
html_theme = 'default'
html_theme = 'nature'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
@ -103,7 +99,7 @@ html_theme = 'default'
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = ['_theme']
html_theme_path = ['_theme']
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
@ -124,7 +120,7 @@ html_short_title = "django-dbtemplates"
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
# html_static_path = ['_static']
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
@ -176,8 +172,8 @@ htmlhelp_basename = 'django-dbtemplatesdoc'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'django-dbtemplates.tex', 'django-dbtemplates Documentation',
'Jannis Leidel and contributors', 'manual'),
('index', 'django-dbtemplates.tex', u'django-dbtemplates Documentation',
u'Jannis Leidel', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of

View file

@ -1,19 +1,10 @@
django-dbtemplates
==================
``dbtemplates`` is a Django app that consists of two parts:
1. It allows you to store templates in your database
2. It provides `template loader`_ that enables Django to load the
templates from the database
It also features optional support for :ref:`versioned storage <versioned>`
and :ref:`django-admin command <commands>`, integrates with Django's
:ref:`caching system <caching>` and the :ref:`admin actions <admin_actions>`.
Please see https://django-dbtemplates.readthedocs.io/ for more details.
The source code and issue tracker can be found on Github: https://github.com/jazzband/django-dbtemplates
``dbtemplates`` is a Django app that comes with to parts: It allows you to
create templates that are saved in your database, and it provides a so called
`template loader`_, a function that enables Django to find the templates you
created in the database.
.. _template loader: http://docs.djangoproject.com/en/dev/ref/templates/api/#loading-templates
@ -23,6 +14,3 @@ Contents:
:maxdepth: 2
overview
advanced
settings
changelog

View file

@ -1,170 +0,0 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\asd.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\asd.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
:end

View file

@ -1,9 +1,28 @@
===================================
Database template loader for Django
===================================
``dbtemplates`` is a Django app that comes with to parts: It allows you to
create templates that are saved in your database, and it provides a so called
`template loader`_, a function that enables Django to find the templates you
created in the database.
It also includes a extensible caching mechanism and supports version control
of the templates saved in the database.
.. _template loader: http://docs.djangoproject.com/en/dev/ref/templates/api/#loading-templates
.. contents:: Table of Contents
:backlinks: none
Setup
=====
1. Get the source from the `Git repository`_ or install it from the
Python Package Index by running ``pip install django-dbtemplates``.
2. Edit the settings.py of your Django site:
1. Get the source from the `Mercurial repository`_ or install it from the
Python Package Index by running ``easy_install django-dbtemplates`` or
``pip django-dbtemplates``.
2. Follow the instructions in the INSTALL file
3. Edit the settings.py of your Django site:
* Add ``dbtemplates`` to the ``INSTALLED_APPS`` setting
@ -23,54 +42,28 @@ Setup
'dbtemplates',
)
* Add ``dbtemplates.loader.Loader`` to the ``TEMPLATES.OPTIONS.loaders`` list
in the settings.py of your Django project.
* Add ``dbtemplates.loader.load_template_source`` to the
``TEMPLATE_LOADERS`` list in the settings.py of your Django project
It should look something like this::
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',
],
},
},
]
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.load_template_source',
'django.template.loaders.app_directories.load_template_source',
'dbtemplates.loader.load_template_source',
)
The order of ``TEMPLATES.OPTIONS.loaders`` is important. In the former
example, templates from the database will be used as a fallback (ie. when
the template does not exists in other locations). If you want the template
from the database to be used to override templates in other locations,
put ``dbtemplates.loader.Loader`` at the beginning of ``loaders``.
4. Sync your database ``python manage.py syncdb``
5. Restart your Django server
3. Sync your database ``python manage.py migrate``
4. Restart your Django server
.. _Git repository: https://github.com/jazzband/django-dbtemplates/
.. _Mercurial repository: http://bitbucket.org/jezdez/django-dbtemplates/
Usage
=====
Creating database templates is pretty simple: Just open the admin interface
of your Django-based site in your browser and click on "Templates" in the
"Database templates" section.
"Dbtemplates" section.
There you only need to fill in the ``name`` field with the identifier, Django
is supposed to use while searching for templates, e.g.
@ -84,3 +77,409 @@ other template loaders. For example, if you have a template called
contents in the database, you just need to leave the content field empty to
automatically populate it. That's especially useful if you don't want to
copy and paste its content manually to the textarea.
Example
=======
``dbtemplates`` comes with an example Django project that let's you try it
out. The example uses Django's own `flatpages app`_ to enable you to create
a simple page using ``dbtemplates``. Flat pages are a perfect fit to
dbtemplates since they come prepackaged and are simple to use.
Here is how it works:
1. Open your command line and change to the ``example`` directory in the
directory with the extracted source distribution.
2. Run ``python manage.py syncdb`` and follow the instructions.
3. Run ``python manage.py runserver`` and open your favorite browser with the
address http://127.0.0.1:8000/admin/.
4. Next add a new `Template` object in the ``dbtemplates`` section and use
``flatpages/default.html`` as the value for the ``name`` field. For the
``content`` field use this example::
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>{{ flatpage.title }}</title>
</head>
<body>
{{ flatpage.content }}
</body>
</html>
5. Return to the home screen of the admin interface and add a new flat page.
Use ``/`` (yep, just a forward slash) and whatever ``title`` and
``content`` you prefer. Please make sure you select the default site
``example.com`` before you save the flat page.
6. Visit http://127.0.0.1:8000/ and see the flat page you just created
rendered with the ``flatpages/default.html`` template provided by
``dbtemplates``.
.. _flatpages app: http://docs.djangoproject.com/en/dev/ref/contrib/flatpages/
Settings
========
* ``DBTEMPLATES_ADD_DEFAULT_SITE``
``dbtemplates`` adds the current site (``settings.SITE_ID``) to the database
template when it is created by default. You can disable this feature by
setting ``DBTEMPLATES_ADD_DEFAULT_SITE`` to ``False``.
* ``DBTEMPLATES_CACHE_BACKEND``
The dotted Python path to the cache backend class. See `Caching`_ for
details.
* ``DBTEMPLATES_CACHE_DIR``
A directory path that is used by the cache ``FileSystemBackend`` to store
the cached templates. See `Caching`_ for details.
* ``DBTEMPLATES_USE_CODEMIRROR``
A boolean, if enabled triggers the use of the CodeMirror based editor.
Set to ``False`` by default.
* ``DBTEMPLATES_USE_REVERSION``
A boolean, if enabled triggers the use of ``django-reversion``.
* ``DBTEMPLATES_MEDIA_PREFIX``
The URL prefix for ``dbtemplates``' media -- CSS and JavaScript used by
the CodeMirror based editor. Make sure to use a trailing
slash, and to have this be different from the ``MEDIA_URL`` setting
(since the same URL cannot be mapped onto two different sets of
files).
Caching
=======
Using the default caching
-------------------------
Dbtemplates comes with different backends for caching that are automatically
created, updated and deleted when templates are saved in the database by
using Django's signal framework.
To enable one of them you need to specify a setting called
``DBTEMPLATES_CACHE_BACKEND`` to one of the following values:
* ``dbtemplates.cache.FileSystemBackend`` -- File system caching
The ``FileSystemBackend`` is a simple way to store the templates you have
in the database on the filesystem. That's especially useful if you don't
use a full caching framework like Django is providing.
To use this backend you need additionally create a setting
``DBTEMPLATES_CACHE_DIR`` that contains the full file system path to the
directory where ``dbtemplates`` should create the cache files in.
* ``dbtemplates.cache.DjangoCacheBackend`` -- Django cache
The ``DjangoCacheBackend`` is a thin wrapper around Django's caching
framework that enables you to use advanced caching solutions like
memcached or database caching. Please see the `cache documentation`_ if
you want to know more about it.
.. _cache documentation: http://docs.djangoproject.com/en/dev/topics/cache/#setting-up-the-cache
Writing your own caching backends
---------------------------------
Writing your own cache backends is perfectly easy since ``dbtemplates``
includes a easy-to-use base class in ``dbtemplates.cache.BaseCacheBackend``.
Just subclass that base backend somewhere in your own code and provide the
follwing three reuqired methods:
* ``load``
Loads a template from the cache with the given name and returns its
contents. Return None if nothing found.
Arguments:
* ``name`` - name of the template
* ``save``
Saves the passed template contents with the passed name in the cache.
Arguments:
* ``name`` - name of the template
* ``content`` - contents of the template
* ``remove``
Removes the template with the passed name from the cache.
Arguments:
* ``name`` - name of the template
Please see also the `source of the default backends`_ to see how it works.
.. _source of the default backends: http://bitbucket.org/jezdez/django-dbtemplates/src/tip/dbtemplates/cache.py
Versionizing your templates
===========================
``dbtemplates`` comes prepared to use the third party Django app
`django-reversion`_, that once installed besides ``dbtemplates`` allows you
to jump back to old versions of your templates. It automatically saves every
state when you save the template in your database and provides an easy to use
interface.
Please refer to `django-reversion's documentation`_ for more information
about how it works. ``dbtemplates`` uses ``django-reversion`` if the
``DBTEMPLATES_USE_REVERSION`` setting is ``True``. Just visit the
"History" section of each template instance and browse its history.
Short installation howto
------------------------
1. Get the source from the `django-reversion`_ project site and put it
somewhere on your `PYTHONPATH`.
2. Add ``reversion`` to the ``INSTALLED_APPS`` setting of your Django project
3. Sync your database with ``python manage.py syncdb``
.. _django-reversion: http://code.google.com/p/django-reversion/
.. _django-reversion's documentation: http://code.google.com/p/django-reversion/wiki/GettingStarted
Management commands
===================
``dbtemplates`` comes with two `Django management commands`_ to be used with
``django-admin.py`` or ``manage.py``:
* ``sync_templates``
Enables you to sync your already existing file systems templates with the
database. It will guide you through the whole process.
* ``create_error_templates``
Tries to add the two templates ``404.html`` and ``500.html`` that are used
by Django when a error occurs.
.. _Django management commands: http://docs.djangoproject.com/en/dev/ref/django-admin/
Admin actions
=============
``dbtemplates`` provides two `admin actions`_ to be used with Django>=1.1.
* ``invalidate_cache``
Invalidates the cache of the selected templates by calling the appropriate
cache backend methods.
* ``repopulate_cache``
Repopulates the cache with selected templates by invalidating it first and
filling then after that.
.. _admin actions: http://docs.djangoproject.com/en/1.1/ref/contrib/admin/actions/#ref-contrib-admin-actions
Changelog
=========
0.7.2 (09-04-10)
----------------
* Moved to Github again. Sigh.
0.7.1 (07-07-10)
----------------
* Fixed problem with the CodeMirror textarea, which wasn't completely
disabled before.
* Fixed problem with the ``DBTEMPLATES_MEDIA_PREFIX`` setting, which defaults
now to ``os.path.join(settings.MEDIA_ROOT, 'dbtemplates')`` now.
In other words, if you don't specify a ``DBTEMPLATES_MEDIA_PREFIX`` setting
and have the CodeMirror textarea enabled, dbtemplates will look in a
subdirectory of your site's ``MEDIA_ROOT`` for the CodeMirror media files.
0.7.0 (06-24-10)
----------------
* Added CodeMirror_-based syntax highlighting textarea, based on the amaxing
work_ by `Nic Pottier`_. Set the ``DBTEMPLATES_USE_CODEMIRROR`` setting
to ``True`` to enable it.
* Make use of the full width in plain textarea mode.
* Added Chinese translation
* Added support for Django 1.2
* Updated French translation
* Added ``DBTEMPLATES_USE_REVERSION`` setting to be able to explicitely enable
reversion support. (Default: ``False``)
.. _CodeMirror: http://marijn.haverbeke.nl/codemirror/
.. _work: https://gist.github.com/368758/86bcafe53c438e2e2a0e3442c3b30f2c6011fbba
.. _`Nic Pottier`: http://github.com/nicpottier
0.6.1 (10-19-09):
-----------------
* Fixed issue with default site of a template, added ability to disable
default site (``DBTEMPLATES_ADD_DEFAULT_SITE``).
0.6.0 (10-09-09):
-----------------
* Updated and added locales (Danish, Brazilian Portuguese)
* Fixes an ambiguity problem with the cache invalidation
* Added ``invalidate_cache`` and ``repopulate_cache`` admin actions
* Added Sphinx documentation
0.5.7
-----
* Updates to the docs
* switch back to Bitbucket
* fixed tests
* Added Italian translation
* list of sites the template is used on
* fixed bug in ``create_error_template`` command.
0.5.4
-----
* Made loader and cache backends site-aware.
* The filesystem cache backend now saves the files under
``<dir>/<site_domain>/<file_name>``.
* The Django cache backend the Site id in the cache key
* Template is now saved explicitly to backend if not existent in cache
(e.g. if deleted manually or invalidated).
0.5.3
-----
* Removed automatic creation of 404.html and 500.html templates and added a
new management command for those cases called ``create_error_templates``
* Also reverted move to Bitbucket
0.5.2
-----
* Fixed a problem with ``django.contrib.sites`` when its table hasn't been
populated yet on initialization of dbtemplates. Thanks for the report,
Kevin Fricovsky
* Added an example Django project and docs for it
0.5.1
-----
* Removed unneeded code that registered the model with reversion.
* Updated docs a bit.
* Moved codebase to Bitbucket.
* Removed legacy ``sync_templates.py`` script, use ``django-admin.py
sync_templates`` from now on.
0.5.0
-----
* Added support for `django-reversion`_
* added feature that populates the content field automatically when left
empty by using Django's other template loaders
* added caching backend system with two default backends:
* ``FileSystemBackend``
* ``DjangoCacheBackend``
More about it in the `blog post`_ and in the docs.
.. _django-reversion: http://code.google.com/p/django-reversion/
.. _blog post: http://jannisleidel.com/2008/11/updates-to-django-dbtemplates-and-half-assed-promise/
0.4.7
-----
* Minor bugfix
0.4.6
-----
* Minor doc change and PyPI support
0.4.5
-----
* fixed the --force option of the sync_templates command
0.4.4
-----
* fixed error in custom model save() after changes in Django `r8670`_.
.. _r8670: http://code.djangoproject.com/changeset/8670
0.4.3
-----
* removed oldforms code
0.4.2
-----
* added Hebrew translation (by mkriheli)
0.4.1
-----
* added French (by Roland Frederic) and German locale
0.4.0
-----
* adds better support for newforms-admin
* don't forget to load the dbtemplates.admin, e.g. by using
django.contrib.admin.autodiscover() in you urls.py
0.3.1
-----
* adds a new management command *sync_templates* for bidirectional syncing
between filesystem and database (backwards-compatible) and
FilesystemCaching (thanks, Arne Brodowski!)
0.2.5
-----
* adds support for newforms-admin
Support
=======
Please leave your questions and messages on the designated site:
http://github.com/jezdez/django-dbtemplates/issues/

View file

@ -1,65 +0,0 @@
Settings
========
``DBTEMPLATES_ADD_DEFAULT_SITE``
--------------------------------
``dbtemplates`` adds the current site (``settings.SITE_ID``) to the database
template when it is created by default. You can disable this feature by
setting ``DBTEMPLATES_ADD_DEFAULT_SITE`` to ``False``.
``DBTEMPLATES_AUTO_POPULATE_CONTENT``
-------------------------------------
``dbtemplates`` auto-populates the content of a newly created template with
the content of a template with the same name the other template loader.
To disable this feature set ``DBTEMPLATES_AUTO_POPULATE_CONTENT`` to
``False``.
``DBTEMPLATES_CACHE_BACKEND``
-----------------------------
The dotted Python path to the cache backend class. See
:ref:`Caching <caching>` for details.
``DBTEMPLATES_USE_CODEMIRROR``
------------------------------
A boolean, if enabled triggers the use of the CodeMirror based editor.
Set to ``False`` by default.
``DBTEMPLATES_USE_TINYMCE``
---------------------------
.. versionadded:: 1.3
A boolean, if enabled triggers the use of the TinyMCE based editor.
Set to ``False`` by default.
``DBTEMPLATES_USE_REVERSION``
-----------------------------
A boolean, if enabled triggers the use of ``django-reversion``.
``DBTEMPLATES_USE_REVERSION_COMPARE``
-----------------------------
A boolean, if enabled triggers the use of ``django-reversion-compare``.
``DBTEMPLATES_MEDIA_PREFIX``
----------------------------
The URL prefix for ``dbtemplates``' media -- CSS and JavaScript used by
the CodeMirror based editor. Make sure to use a trailing
slash, and to have this be different from the ``STATIC_URL`` setting
(since the same URL cannot be mapped onto two different sets of
files).
.. warning::
Starting in version 1.0, ``dbtemplates`` uses the ``STATIC_URL`` setting,
originally introduced by the django-staticfiles_ app. The app has since
been added to Django itself and isn't needed if you use Django 1.3 or
higher. Please refer to the `contrib docs`_ in that case.
.. _django-staticfiles: http://pypi.python.org/pypi/django-staticfiles
.. _contrib docs: http://docs.djangoproject.com/en/dev/ref/staticfiles/

15
example/manage.py Executable file
View file

@ -0,0 +1,15 @@
#!/usr/bin/env python
import os, sys
from django.core.management import execute_manager
sys.path.insert(0, os.path.abspath('./..'))
try:
import settings # Assumed to be in the same directory.
except ImportError:
import sys
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
sys.exit(1)
if __name__ == "__main__":
execute_manager(settings)

1
example/requirements.txt Normal file
View file

@ -0,0 +1 @@
django-staticfiles

106
example/settings.py Normal file
View file

@ -0,0 +1,106 @@
# Django settings for example project.
import os, posixpath
PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
DEBUG = True
TEMPLATE_DEBUG = DEBUG
ADMINS = (
# ('Your Name', 'your_email@domain.com'),
)
MANAGERS = ADMINS
DATABASE_ENGINE = 'sqlite3' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
DATABASE_NAME = 'example.db' # Or path to database file if using sqlite3.
DATABASE_USER = '' # Not used with sqlite3.
DATABASE_PASSWORD = '' # Not used with sqlite3.
DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3.
DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'America/Chicago'
# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'
SITE_ID = 1
# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True
# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = os.path.join(PROJECT_ROOT, "site_media", "media")
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
# Examples: "http://media.lawrence.com", "http://example.com/media/"
MEDIA_URL = "/site_media/media/"
# Absolute path to the directory that holds static files like app media.
# Example: "/home/media/media.lawrence.com/apps/"
STATIC_ROOT = os.path.join(PROJECT_ROOT, "site_media", "static")
# URL that handles the static files like app media.
# Example: "http://media.lawrence.com"
STATIC_URL = "/site_media/static/"
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = posixpath.join(STATIC_URL, "admin/")
# Make this unique, and don't share it with anybody.
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',
)
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
)
ROOT_URLCONF = 'example.urls'
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.admin',
'django.contrib.flatpages',
'dbtemplates',
'staticfiles',
#'reversion',
)
# Uncomment the following two settings to use the file system cache backend.
# It will cache in the directory "cache" inside the example project directory.
#DBTEMPLATES_CACHE_BACKEND = "dbtemplates.cache.FileSystemBackend"
#DBTEMPLATES_CACHE_DIR = "cache"
DBTEMPLATES_MEDIA_PREFIX = posixpath.join(STATIC_URL, "dbtemplates/")
DBTEMPLATES_USE_CODEMIRROR = True

24
example/urls.py Normal file
View file

@ -0,0 +1,24 @@
from django.conf import settings
from django.conf.urls.defaults import patterns, include
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Example:
# (r'^example/', include('example.foo.urls')),
# Uncomment the admin/doc line below and add 'django.contrib.admindocs'
# to INSTALLED_APPS to enable admin documentation:
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),
# Uncomment the next line to enable the admin:
(r'^admin/(.*)', admin.site.root),
)
# the following is used to serve up local media files like images
if settings.DEBUG:
urlpatterns += patterns("",
(r"", include("staticfiles.urls")),
)

View file

@ -1,51 +0,0 @@
[build-system]
requires = [
"setuptools>=61.2",
"setuptools_scm",
]
build-backend = "setuptools.build_meta"
[project]
name = "django-dbtemplates"
authors = [{name = "Jannis Leidel", email = "jannis@leidel.info"}]
description = "Template loader for templates stored in the database"
readme = "README.rst"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Environment :: Web Environment",
"Intended Audience :: Developers",
"License :: OSI Approved :: BSD License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Framework :: Django",
]
requires-python = ">=3.8"
dependencies = ["django-appconf >= 0.4"]
dynamic = ["version"]
[project.urls]
Documentation = "https://django-dbtemplates.readthedocs.io/"
Changelog = "https://django-dbtemplates.readthedocs.io/en/latest/changelog.html"
Source = "https://github.com/jazzband/django-dbtemplates"
[tool.setuptools]
zip-safe = false
include-package-data = false
[tool.setuptools.packages]
find = {namespaces = false}
[tool.setuptools.package-data]
dbtemplates = [
"locale/*/LC_MESSAGES/*",
"static/dbtemplates/css/*.css",
"static/dbtemplates/js/*.js",
]

View file

@ -1 +0,0 @@
django

View file

@ -1,2 +0,0 @@
flake8
coverage

13
setup.cfg Normal file
View file

@ -0,0 +1,13 @@
[egg_info]
#tag_build = a1
[build_sphinx]
source-dir = docs/
build-dir = docs/_build
all_files = 1
[upload_docs]
upload-dir = docs/_build/html
[upload_sphinx]
upload-dir = docs/_build/html

29
setup.py Normal file
View file

@ -0,0 +1,29 @@
from setuptools import setup, find_packages
setup(
name='django-dbtemplates',
version=__import__('dbtemplates').__version__,
description='Template loader for database stored templates with extensible cache backend',
long_description=open('docs/overview.txt').read(),
author='Jannis Leidel',
author_email='jannis@leidel.info',
url='http://packages.python.org/django-dbtemplates/',
packages=find_packages(exclude=['example']),
zip_safe=False,
package_data = {
'dbtemplates': [
'locale/*/LC_MESSAGES/*',
'media/dbtemplates/css/*.css',
'media/dbtemplates/js/*.js',
],
},
classifiers=[
'Development Status :: 4 - Beta',
'Environment :: Web Environment',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Framework :: Django',
]
)

61
tox.ini
View file

@ -1,61 +0,0 @@
[tox]
minversion = 4.0
envlist =
flake8
py3{8,9,10,11,12}-dj42
py3{10,11,12}-dj{50}
py3{10,11,12,13}-dj{51,52}
py3{12,13}-dj{main}
coverage
[gh-actions]
python =
3.8: py38
3.9: py39
3.10: py310
3.10: py310, flake8
3.11: py311
3.12: py312
3.13: py313
[testenv]
skipsdist = true
package = editable
basepython =
py38: python3.8
py39: python3.9
py310: python3.10
py311: python3.11
py312: python3.12
py313: python3.13
setenv =
DJANGO_SETTINGS_MODULE = dbtemplates.test_settings
deps =
-r requirements/tests.txt
dj42: Django>=4.2,<4.3
dj50: Django>=5.0,<5.1
dj51: Django>=5.1,<5.2
dj52: Django>=5.2,<5.3
djmain: https://github.com/django/django/archive/main.tar.gz#egg=django
commands =
python --version
python -c "import django ; print(django.VERSION)"
coverage run --branch --parallel-mode {envbindir}/django-admin test -v2 {posargs:dbtemplates}
[testenv:coverage]
basepython = python3.10
deps = coverage
commands =
coverage combine
coverage report
coverage xml
[testenv:flake8]
basepython = python3.10
commands = flake8 dbtemplates
deps = flake8
[flake8]
exclude=.tox
ignore=E501,E127,E128,E124