mirror of
https://github.com/jazzband/django-dbtemplates.git
synced 2026-03-16 22:20:28 +00:00
Format with ruff
This commit is contained in:
parent
2c8e80bc6e
commit
58e88b1f18
15 changed files with 367 additions and 263 deletions
|
|
@ -14,8 +14,7 @@ from dbtemplates.utils.template import check_template_syntax
|
|||
# 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
|
||||
from reversion_compare.admin import CompareVersionAdmin as TemplateModelAdmin
|
||||
elif settings.DBTEMPLATES_USE_REVERSION:
|
||||
from reversion.admin import VersionAdmin as TemplateModelAdmin
|
||||
else:
|
||||
|
|
@ -23,22 +22,22 @@ else:
|
|||
|
||||
|
||||
class CodeMirrorTextArea(forms.Textarea):
|
||||
|
||||
"""
|
||||
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(settings.DBTEMPLATES_MEDIA_PREFIX, "css/editor.css")]
|
||||
)
|
||||
js = [posixpath.join(settings.DBTEMPLATES_MEDIA_PREFIX, "js/codemirror.js")]
|
||||
|
||||
def render(self, name, value, attrs=None, renderer=None):
|
||||
result = []
|
||||
result.append(super().render(name, value, attrs))
|
||||
result.append(
|
||||
super().render(name, value, attrs))
|
||||
result.append("""
|
||||
"""
|
||||
<script type="text/javascript">
|
||||
var editor = CodeMirror.fromTextArea('id_%(name)s', {
|
||||
path: "%(media_prefix)sjs/",
|
||||
|
|
@ -51,7 +50,9 @@ class CodeMirrorTextArea(forms.Textarea):
|
|||
lineNumbers: true
|
||||
});
|
||||
</script>
|
||||
""" % dict(media_prefix=settings.DBTEMPLATES_MEDIA_PREFIX, name=name))
|
||||
"""
|
||||
% dict(media_prefix=settings.DBTEMPLATES_MEDIA_PREFIX, name=name)
|
||||
)
|
||||
return mark_safe("".join(result))
|
||||
|
||||
|
||||
|
|
@ -61,62 +62,79 @@ 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.")
|
||||
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.")
|
||||
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(attrs={"rows": "24"}),
|
||||
help_text=content_help_text,
|
||||
required=False,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Template
|
||||
fields = ('name', 'content', 'sites', 'creation_date', 'last_changed')
|
||||
fields = ("name", "content", "sites", "creation_date", "last_changed")
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class TemplateAdmin(TemplateModelAdmin):
|
||||
form = TemplateAdminForm
|
||||
readonly_fields = ['creation_date', 'last_changed']
|
||||
readonly_fields = ["creation_date", "last_changed"]
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'fields': ('name', 'content'),
|
||||
'classes': ('monospace',),
|
||||
}),
|
||||
(_('Advanced'), {
|
||||
'fields': (('sites'),),
|
||||
}),
|
||||
(_('Date/time'), {
|
||||
'fields': (('creation_date', 'last_changed'),),
|
||||
'classes': ('collapse',),
|
||||
}),
|
||||
(
|
||||
None,
|
||||
{
|
||||
"fields": ("name", "content"),
|
||||
"classes": ("monospace",),
|
||||
},
|
||||
),
|
||||
(
|
||||
_("Advanced"),
|
||||
{
|
||||
"fields": (("sites"),),
|
||||
},
|
||||
),
|
||||
(
|
||||
_("Date/time"),
|
||||
{
|
||||
"fields": (("creation_date", "last_changed"),),
|
||||
"classes": ("collapse",),
|
||||
},
|
||||
),
|
||||
)
|
||||
filter_horizontal = ('sites',)
|
||||
list_display = ('name', 'creation_date', 'last_changed', 'site_list')
|
||||
list_filter = ('sites',)
|
||||
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']
|
||||
search_fields = ("name", "content")
|
||||
actions = ["invalidate_cache", "repopulate_cache", "check_syntax"]
|
||||
|
||||
def invalidate_cache(self, request, queryset):
|
||||
for template in queryset:
|
||||
|
|
@ -125,10 +143,11 @@ class TemplateAdmin(TemplateModelAdmin):
|
|||
message = ngettext(
|
||||
"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")
|
||||
count,
|
||||
)
|
||||
self.message_user(request, message % {"count": count})
|
||||
|
||||
invalidate_cache.short_description = _("Invalidate cache of selected templates")
|
||||
|
||||
def repopulate_cache(self, request, queryset):
|
||||
for template in queryset:
|
||||
|
|
@ -137,37 +156,43 @@ class TemplateAdmin(TemplateModelAdmin):
|
|||
message = ngettext(
|
||||
"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")
|
||||
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}')
|
||||
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)})
|
||||
"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})
|
||||
"Template syntax OK for %(count)d templates.",
|
||||
count,
|
||||
)
|
||||
self.message_user(request, message % {"count": count})
|
||||
|
||||
check_syntax.short_description = _("Check template syntax")
|
||||
|
||||
def site_list(self, template):
|
||||
return ", ".join([site.name for site in template.sites.all()])
|
||||
site_list.short_description = _('sites')
|
||||
|
||||
site_list.short_description = _("sites")
|
||||
|
||||
|
||||
admin.site.register(Template, TemplateAdmin)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ from django.utils.translation import gettext_lazy as _
|
|||
|
||||
|
||||
class DBTemplatesConfig(AppConfig):
|
||||
name = 'dbtemplates'
|
||||
verbose_name = _('Database templates')
|
||||
name = "dbtemplates"
|
||||
verbose_name = _("Database templates")
|
||||
|
||||
default_auto_field = 'django.db.models.AutoField'
|
||||
default_auto_field = "django.db.models.AutoField"
|
||||
|
|
|
|||
|
|
@ -33,35 +33,45 @@ class DbTemplatesConf(AppConf):
|
|||
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.")
|
||||
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.")
|
||||
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.")
|
||||
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.")
|
||||
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.")
|
||||
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
|
||||
|
|
|
|||
|
|
@ -4,8 +4,12 @@ from django.template import Origin, TemplateDoesNotExist
|
|||
from django.template.loaders.base import Loader as BaseLoader
|
||||
|
||||
from dbtemplates.models import Template
|
||||
from dbtemplates.utils.cache import (cache, get_cache_key,
|
||||
set_and_return, get_cache_notfound_key)
|
||||
from dbtemplates.utils.cache import (
|
||||
cache,
|
||||
get_cache_key,
|
||||
set_and_return,
|
||||
get_cache_notfound_key,
|
||||
)
|
||||
|
||||
|
||||
class Loader(BaseLoader):
|
||||
|
|
@ -17,6 +21,7 @@ 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):
|
||||
|
|
@ -30,11 +35,10 @@ class Loader(BaseLoader):
|
|||
content, _ = self._load_template_source(origin.template_name)
|
||||
return content
|
||||
|
||||
def _load_and_store_template(self, template_name, cache_key, site,
|
||||
**params):
|
||||
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}'
|
||||
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):
|
||||
|
|
@ -74,15 +78,17 @@ class Loader(BaseLoader):
|
|||
# Not marked as not-found, move on...
|
||||
|
||||
try:
|
||||
return self._load_and_store_template(template_name, cache_key,
|
||||
site, sites__in=[site.id])
|
||||
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)
|
||||
return self._load_and_store_template(
|
||||
template_name, cache_key, site, sites__isnull=True
|
||||
)
|
||||
except (Template.MultipleObjectsReturned, Template.DoesNotExist):
|
||||
pass
|
||||
|
||||
# Mark as not-found in cache.
|
||||
cache.set(cache_notfound_key, '1')
|
||||
cache.set(cache_notfound_key, "1")
|
||||
raise TemplateDoesNotExist(template_name)
|
||||
|
|
|
|||
|
|
@ -12,8 +12,9 @@ class Command(BaseCommand):
|
|||
for template in Template.objects.all():
|
||||
valid, error = check_template_syntax(template)
|
||||
if not valid:
|
||||
errors.append(f'{template.name}: {error}')
|
||||
errors.append(f"{template.name}: {error}")
|
||||
if errors:
|
||||
raise CommandError(
|
||||
'Some templates contained errors\n%s' % '\n'.join(errors))
|
||||
self.stdout.write('OK')
|
||||
"Some templates contained errors\n%s" % "\n".join(errors)
|
||||
)
|
||||
self.stdout.write("OK")
|
||||
|
|
|
|||
|
|
@ -29,29 +29,39 @@ class Command(BaseCommand):
|
|||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
"-f", "--force", action="store_true", dest="force",
|
||||
default=False, help="overwrite existing database templates")
|
||||
"-f",
|
||||
"--force",
|
||||
action="store_true",
|
||||
dest="force",
|
||||
default=False,
|
||||
help="overwrite existing database templates",
|
||||
)
|
||||
|
||||
def handle(self, **options):
|
||||
force = options.get('force')
|
||||
force = options.get("force")
|
||||
try:
|
||||
site = Site.objects.get_current()
|
||||
except Site.DoesNotExist:
|
||||
raise CommandError("Please make sure to have the sites contrib "
|
||||
"app installed and setup with a site object")
|
||||
raise CommandError(
|
||||
"Please make sure to have the sites contrib "
|
||||
"app installed and setup with a site object"
|
||||
)
|
||||
|
||||
verbosity = int(options.get('verbosity', 1))
|
||||
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=f"{error_code}.html"
|
||||
)
|
||||
if created or (not created and force):
|
||||
template.content = TEMPLATES.get(error_code, '')
|
||||
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)
|
||||
sys.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)
|
||||
sys.stderr.write(
|
||||
"A template for %s errors already exists.\n" % error_code
|
||||
)
|
||||
|
|
|
|||
|
|
@ -108,7 +108,9 @@ class Command(BaseCommand):
|
|||
"" % (name, path)
|
||||
)
|
||||
if force or confirm.lower().startswith("y"):
|
||||
t = Template.objects.create(name=name, content=path.read_text(encoding="utf-8"))
|
||||
t = Template.objects.create(
|
||||
name=name, content=path.read_text(encoding="utf-8")
|
||||
)
|
||||
t.sites.add(site)
|
||||
else:
|
||||
while True:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ from django.db import migrations, models
|
|||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("sites", "0001_initial"),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -4,20 +4,19 @@ from django.db import migrations, models
|
|||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dbtemplates', '0001_initial'),
|
||||
("dbtemplates", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='template',
|
||||
name='creation_date',
|
||||
field=models.DateTimeField(auto_now_add=True, verbose_name='creation date'),
|
||||
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'),
|
||||
model_name="template",
|
||||
name="last_changed",
|
||||
field=models.DateTimeField(auto_now=True, verbose_name="last changed"),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -18,24 +18,26 @@ 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,
|
||||
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)
|
||||
|
||||
id = models.AutoField(
|
||||
primary_key=True, verbose_name=_("ID"), serialize=False, auto_created=True
|
||||
)
|
||||
name = models.CharField(
|
||||
_("name"), max_length=100, help_text=_("Example: 'flatpages/default.html'")
|
||||
)
|
||||
content = models.TextField(_("content"), blank=True)
|
||||
sites = models.ManyToManyField(Site, verbose_name=_("sites"), blank=True)
|
||||
creation_date = models.DateTimeField(_("creation date"), auto_now_add=True)
|
||||
last_changed = models.DateTimeField(_("last changed"), auto_now=True)
|
||||
|
||||
objects = models.Manager()
|
||||
on_site = CurrentSiteManager('sites')
|
||||
on_site = CurrentSiteManager("sites")
|
||||
|
||||
class Meta:
|
||||
db_table = 'django_template'
|
||||
verbose_name = _('template')
|
||||
verbose_name_plural = _('templates')
|
||||
ordering = ('name',)
|
||||
db_table = "django_template"
|
||||
verbose_name = _("template")
|
||||
verbose_name_plural = _("templates")
|
||||
ordering = ("name",)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
|
|
|||
|
|
@ -16,9 +16,13 @@ from django.contrib.sites.models import Site
|
|||
from dbtemplates.conf import settings
|
||||
from dbtemplates.loader import Loader
|
||||
from dbtemplates.models import Template, add_default_site
|
||||
from dbtemplates.utils.cache import cache, get_cache_backend, get_cache_key, set_and_return
|
||||
from dbtemplates.utils.template import (get_template_source,
|
||||
check_template_syntax)
|
||||
from dbtemplates.utils.cache import (
|
||||
cache,
|
||||
get_cache_backend,
|
||||
get_cache_key,
|
||||
set_and_return,
|
||||
)
|
||||
from dbtemplates.utils.template import get_template_source, check_template_syntax
|
||||
from dbtemplates.management.commands import sync_templates
|
||||
|
||||
|
||||
|
|
@ -33,7 +37,7 @@ def handle_add_default_site(sender, setting, value, **kwargs):
|
|||
|
||||
@contextmanager
|
||||
def temptemplate(name: str, cleanup: bool = True):
|
||||
temp_template_dir = Path(tempfile.mkdtemp('dbtemplates'))
|
||||
temp_template_dir = Path(tempfile.mkdtemp("dbtemplates"))
|
||||
temp_template_path = temp_template_dir / name
|
||||
try:
|
||||
yield temp_template_path
|
||||
|
|
@ -44,7 +48,9 @@ def temptemplate(name: str, cleanup: bool = True):
|
|||
class DbTemplatesCacheTestCase(TestCase):
|
||||
def test_set_and_return(self):
|
||||
self.assertTrue(bool(cache))
|
||||
rtn = set_and_return("this_is_the_cache_key", "cache test content", "cache display name")
|
||||
rtn = set_and_return(
|
||||
"this_is_the_cache_key", "cache test content", "cache display name"
|
||||
)
|
||||
self.assertEqual(rtn, ("cache test content", "cache display name"))
|
||||
self.assertEqual(cache.get("this_is_the_cache_key"), "cache test content")
|
||||
|
||||
|
|
@ -57,13 +63,13 @@ class BaseDbTemplatesTestCase(TestCase):
|
|||
)
|
||||
def setUp(self):
|
||||
self.site1, created1 = Site.objects.get_or_create(
|
||||
domain="example.com", name="example.com")
|
||||
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')
|
||||
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)
|
||||
|
||||
|
||||
|
|
@ -71,33 +77,38 @@ class DbTemplatesLoaderTestCase(BaseDbTemplatesTestCase):
|
|||
def test_load_and_store_template(self):
|
||||
from django.template.loader import _engine_list
|
||||
from django.core.cache import CacheKeyWarning
|
||||
|
||||
loader = Loader(_engine_list()[0])
|
||||
with self.assertWarns(CacheKeyWarning):
|
||||
rtn = loader._load_and_store_template('base.html', 'base template cache key', self.site1)
|
||||
self.assertEqual(rtn, ('base', f'dbtemplates:default:base.html:example.com'))
|
||||
rtn = loader._load_and_store_template(
|
||||
"base.html", "base template cache key", self.site1
|
||||
)
|
||||
self.assertEqual(rtn, ("base", "dbtemplates:default:base.html:example.com"))
|
||||
|
||||
@override_settings(DBTEMPLATES_ADD_DEFAULT_SITE=False)
|
||||
def test_load_templates_sites(self):
|
||||
t_site1 = Template.objects.create(
|
||||
name='copyright.html', content='(c) example.com')
|
||||
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')
|
||||
name="copyright.html", content="(c) example.org"
|
||||
)
|
||||
t_site2.sites.add(self.site2)
|
||||
|
||||
new_site = Site.objects.create(
|
||||
domain="example.net", name="example.net")
|
||||
new_site = Site.objects.create(domain="example.net", name="example.net")
|
||||
with self.settings(SITE_ID=new_site.id):
|
||||
Site.objects.clear_cache()
|
||||
|
||||
self.assertRaises(TemplateDoesNotExist,
|
||||
loader.get_template, "copyright.html")
|
||||
self.assertRaises(
|
||||
TemplateDoesNotExist, loader.get_template, "copyright.html"
|
||||
)
|
||||
|
||||
def test_load_templates(self):
|
||||
result = loader.get_template("base.html").render()
|
||||
self.assertEqual(result, 'base')
|
||||
self.assertEqual(result, "base")
|
||||
result2 = loader.get_template("sub.html").render()
|
||||
self.assertEqual(result2, 'sub')
|
||||
self.assertEqual(result2, "sub")
|
||||
|
||||
def test_cache_invalidation(self):
|
||||
# Add t1 into the cache of site2
|
||||
|
|
@ -123,52 +134,61 @@ class DbTemplatesLoaderTestCase(BaseDbTemplatesTestCase):
|
|||
|
||||
class DbTemplatesModelsTestCase(BaseDbTemplatesTestCase):
|
||||
def test_basics(self):
|
||||
self.assertQuerySetEqual(self.t1.sites.all(), Site.objects.filter(id=self.site1.id))
|
||||
self.assertQuerySetEqual(
|
||||
self.t1.sites.all(), Site.objects.filter(id=self.site1.id)
|
||||
)
|
||||
self.assertIn("base", self.t1.content)
|
||||
self.assertEqual(str(self.t1), self.t1.name)
|
||||
self.assertEqual(str(self.t2), self.t2.name)
|
||||
self.assertQuerySetEqual(Template.objects.filter(sites=self.site1),
|
||||
Template.objects.filter(id__in=[self.t1.id, self.t2.id]))
|
||||
self.assertQuerySetEqual(self.t2.sites.all(), Site.objects.filter(id__in=[self.site1.id, self.site2.id]))
|
||||
self.assertQuerySetEqual(
|
||||
Template.objects.filter(sites=self.site1),
|
||||
Template.objects.filter(id__in=[self.t1.id, self.t2.id]),
|
||||
)
|
||||
self.assertQuerySetEqual(
|
||||
self.t2.sites.all(),
|
||||
Site.objects.filter(id__in=[self.site1.id, self.site2.id]),
|
||||
)
|
||||
|
||||
def test_populate(self):
|
||||
t0 = Template.objects.create(name='header.html', content='<h1>This is a header</h1>')
|
||||
t0 = Template.objects.create(
|
||||
name="header.html", content="<h1>This is a header</h1>"
|
||||
)
|
||||
t0.populate()
|
||||
self.assertEqual(t0.content, "<h1>This is a header</h1>")
|
||||
t0.populate(name='header.html')
|
||||
t0.populate(name="header.html")
|
||||
self.assertEqual(t0.content, "<h1>This is a header</h1>")
|
||||
|
||||
with temptemplate('temp_test.html') as temp_template_path:
|
||||
temp_template_path.write_text('temp test')
|
||||
(temp_template_path.parent / 'temp_test_2.html').write_text('temp test 2')
|
||||
with temptemplate("temp_test.html") as temp_template_path:
|
||||
temp_template_path.write_text("temp test")
|
||||
(temp_template_path.parent / "temp_test_2.html").write_text("temp test 2")
|
||||
NEW_TEMPLATES = settings.TEMPLATES.copy()
|
||||
NEW_TEMPLATES[0]['DIRS'] = (temp_template_path.parent,)
|
||||
NEW_TEMPLATES[0]["DIRS"] = (temp_template_path.parent,)
|
||||
with self.settings(TEMPLATES=NEW_TEMPLATES):
|
||||
t1 = Template.objects.create(name='temp_test.html')
|
||||
t1 = Template.objects.create(name="temp_test.html")
|
||||
t1.populate()
|
||||
self.assertEqual(t1.content, "temp test")
|
||||
t2 = Template.objects.create(name='temp_test.html')
|
||||
t2.populate(name='temp_test_2.html')
|
||||
t2 = Template.objects.create(name="temp_test.html")
|
||||
t2.populate(name="temp_test_2.html")
|
||||
self.assertEqual(t2.content, "temp test 2")
|
||||
t3 = Template.objects.create(name='temp_test_3.html')
|
||||
self.assertIsNone(t3.populate(name='temp_test_doesnt_exist.html'))
|
||||
t3 = Template.objects.create(name="temp_test_3.html")
|
||||
self.assertIsNone(t3.populate(name="temp_test_doesnt_exist.html"))
|
||||
self.assertEqual(t3.content, "")
|
||||
|
||||
@override_settings(DBTEMPLATES_ADD_DEFAULT_SITE=False)
|
||||
def test_empty_sites(self):
|
||||
self.t3 = Template.objects.create(
|
||||
name='footer.html', content='footer')
|
||||
self.t3 = Template.objects.create(name="footer.html", content="footer")
|
||||
self.assertQuerySetEqual(self.t3.sites.all(), self.t3.sites.none())
|
||||
|
||||
def test_error_templates_creation(self):
|
||||
call_command('create_error_templates', force=True, verbosity=0)
|
||||
self.assertQuerySetEqual(Template.objects.filter(sites=self.site1),
|
||||
Template.objects.filter())
|
||||
self.assertTrue(Template.objects.filter(name='404.html').exists())
|
||||
call_command("create_error_templates", force=True, verbosity=0)
|
||||
self.assertQuerySetEqual(
|
||||
Template.objects.filter(sites=self.site1), 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')
|
||||
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_get_cache(self):
|
||||
|
|
@ -176,40 +196,63 @@ class DbTemplatesModelsTestCase(BaseDbTemplatesTestCase):
|
|||
|
||||
def test_check_template_syntax(self):
|
||||
bad_template, _ = Template.objects.get_or_create(
|
||||
name='bad.html', content='{% if foo %}Bar')
|
||||
name="bad.html", content="{% if foo %}Bar"
|
||||
)
|
||||
good_template, _ = Template.objects.get_or_create(
|
||||
name='good.html', content='{% if foo %}Bar{% endif %}')
|
||||
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')
|
||||
self.assertEqual(
|
||||
get_cache_key("name with spaces"), "dbtemplates::name-with-spaces::1"
|
||||
)
|
||||
|
||||
|
||||
class DbTemplatesSyncTemplatesCommandTestCase(TestCase):
|
||||
def test_sync_templates(self):
|
||||
with temptemplate('temp_test.html') as temp_template_path:
|
||||
temp_template_path.write_text('temp test', encoding='utf-8')
|
||||
with temptemplate("temp_test.html") as temp_template_path:
|
||||
temp_template_path.write_text("temp test", encoding="utf-8")
|
||||
NEW_TEMPLATES = settings.TEMPLATES.copy()
|
||||
NEW_TEMPLATES[0]['DIRS'] = sync_templates.DIRS = (temp_template_path.parent,)
|
||||
NEW_TEMPLATES[0]["DIRS"] = sync_templates.DIRS = (
|
||||
temp_template_path.parent,
|
||||
)
|
||||
with self.settings(TEMPLATES=NEW_TEMPLATES):
|
||||
self.assertFalse(
|
||||
Template.objects.filter(name='temp_test.html').exists())
|
||||
call_command('sync_templates', force=True,
|
||||
verbosity=0, overwrite=sync_templates.FILES_TO_DATABASE)
|
||||
self.assertTrue(
|
||||
Template.objects.filter(name='temp_test.html').exists())
|
||||
Template.objects.filter(name="temp_test.html").exists()
|
||||
)
|
||||
call_command(
|
||||
"sync_templates",
|
||||
force=True,
|
||||
verbosity=0,
|
||||
overwrite=sync_templates.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 = Template.objects.get(name="temp_test.html")
|
||||
t.content = "temp test modified"
|
||||
t.save()
|
||||
call_command('sync_templates', force=True,
|
||||
verbosity=0, overwrite=sync_templates.DATABASE_TO_FILES)
|
||||
self.assertEqual('temp test modified', temp_template_path.read_text(encoding='utf-8'))
|
||||
call_command(
|
||||
"sync_templates",
|
||||
force=True,
|
||||
verbosity=0,
|
||||
overwrite=sync_templates.DATABASE_TO_FILES,
|
||||
)
|
||||
self.assertEqual(
|
||||
"temp test modified", temp_template_path.read_text(encoding="utf-8")
|
||||
)
|
||||
|
||||
call_command('sync_templates', ext='.html', app_first=True, force=True, verbosity=0,
|
||||
delete=True, overwrite=sync_templates.DATABASE_TO_FILES)
|
||||
call_command(
|
||||
"sync_templates",
|
||||
ext=".html",
|
||||
app_first=True,
|
||||
force=True,
|
||||
verbosity=0,
|
||||
delete=True,
|
||||
overwrite=sync_templates.DATABASE_TO_FILES,
|
||||
)
|
||||
self.assertTrue(temp_template_path.exists())
|
||||
self.assertFalse(
|
||||
Template.objects.filter(name='temp_test.html').exists())
|
||||
Template.objects.filter(name="temp_test.html").exists()
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
DATABASE_ENGINE = 'sqlite3'
|
||||
DATABASE_ENGINE = "sqlite3"
|
||||
# SQLite does not support removing unique constraints (see #28)
|
||||
SOUTH_TESTS_MIGRATE = False
|
||||
|
||||
SITE_ID = 1
|
||||
|
||||
SECRET_KEY = 'something-something'
|
||||
SECRET_KEY = "something-something"
|
||||
|
||||
CACHES = {
|
||||
"default": {
|
||||
|
|
@ -13,43 +13,43 @@ CACHES = {
|
|||
}
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': ':memory:',
|
||||
"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',
|
||||
"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',
|
||||
"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',
|
||||
"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',
|
||||
]
|
||||
}
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
"OPTIONS": {
|
||||
"loaders": TEMPLATE_LOADERS,
|
||||
"context_processors": [
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ 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
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
from django.template import (Template, TemplateDoesNotExist,
|
||||
TemplateSyntaxError)
|
||||
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)
|
||||
|
|
@ -14,7 +14,7 @@ def get_template_source(name):
|
|||
source = None
|
||||
not_found = []
|
||||
for loader in get_loaders():
|
||||
if loader.__module__.startswith('dbtemplates.'):
|
||||
if loader.__module__.startswith("dbtemplates."):
|
||||
# Don't give a damn about dbtemplates' own loader.
|
||||
continue
|
||||
for origin in loader.get_template_sources(name):
|
||||
|
|
|
|||
96
docs/conf.py
96
docs/conf.py
|
|
@ -15,29 +15,29 @@ 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 -----------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.coverage']
|
||||
extensions = ["sphinx.ext.autodoc", "sphinx.ext.coverage"]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
templates_path = ["_templates"]
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.txt'
|
||||
source_suffix = ".txt"
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8'
|
||||
# source_encoding = 'utf-8'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
master_doc = "index"
|
||||
|
||||
# General information about the project.
|
||||
project = 'django-dbtemplates'
|
||||
copyright = '2007-2019, Jannis Leidel and contributors'
|
||||
project = "django-dbtemplates"
|
||||
copyright = "2007-2019, Jannis Leidel and contributors"
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
|
|
@ -46,61 +46,62 @@ copyright = '2007-2019, Jannis Leidel and contributors'
|
|||
# The short X.Y version.
|
||||
try:
|
||||
from dbtemplates import __version__
|
||||
|
||||
# The short X.Y version.
|
||||
version = '.'.join(__version__.split('.')[:2])
|
||||
version = ".".join(__version__.split(".")[:2])
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = __version__
|
||||
except ImportError:
|
||||
version = release = 'dev'
|
||||
version = release = "dev"
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
# language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
# today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of documents that shouldn't be included in the build.
|
||||
#unused_docs = []
|
||||
# unused_docs = []
|
||||
|
||||
# List of directories, relative to source directory, that shouldn't be searched
|
||||
# for source files.
|
||||
exclude_trees = ['_build']
|
||||
exclude_trees = ["_build"]
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
# default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
# add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
# add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
# show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
pygments_style = "sphinx"
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
# modindex_common_prefix = []
|
||||
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
# 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 = "default"
|
||||
|
||||
# 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
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
# html_theme_path = ['_theme']
|
||||
|
|
@ -114,12 +115,12 @@ html_short_title = "django-dbtemplates"
|
|||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
# html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
# html_favicon = None
|
||||
|
||||
# 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,
|
||||
|
|
@ -128,71 +129,76 @@ html_short_title = "django-dbtemplates"
|
|||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
# html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
# html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
# html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
# html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_use_modindex = True
|
||||
# html_use_modindex = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
# html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
# html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
# html_show_sourcelink = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
# html_use_opensearch = ''
|
||||
|
||||
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = ''
|
||||
# html_file_suffix = ''
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'django-dbtemplatesdoc'
|
||||
htmlhelp_basename = "django-dbtemplatesdoc"
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
# The paper size ('letter' or 'a4').
|
||||
#latex_paper_size = 'letter'
|
||||
# latex_paper_size = 'letter'
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#latex_font_size = '10pt'
|
||||
# latex_font_size = '10pt'
|
||||
|
||||
# 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",
|
||||
"django-dbtemplates Documentation",
|
||||
"Jannis Leidel and contributors",
|
||||
"manual",
|
||||
),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
# latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
# latex_use_parts = False
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#latex_preamble = ''
|
||||
# latex_preamble = ''
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
# latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_use_modindex = True
|
||||
# latex_use_modindex = True
|
||||
|
|
|
|||
Loading…
Reference in a new issue