diff --git a/dbtemplates/admin.py b/dbtemplates/admin.py index f6d65af..9b782d0 100644 --- a/dbtemplates/admin.py +++ b/dbtemplates/admin.py @@ -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(""" + """ -""" % 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) diff --git a/dbtemplates/apps.py b/dbtemplates/apps.py index 9f75273..a98ba83 100644 --- a/dbtemplates/apps.py +++ b/dbtemplates/apps.py @@ -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" diff --git a/dbtemplates/conf.py b/dbtemplates/conf.py index 010db5b..77b5d08 100644 --- a/dbtemplates/conf.py +++ b/dbtemplates/conf.py @@ -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 diff --git a/dbtemplates/loader.py b/dbtemplates/loader.py index 243da31..30e9dbb 100644 --- a/dbtemplates/loader.py +++ b/dbtemplates/loader.py @@ -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) diff --git a/dbtemplates/management/commands/check_template_syntax.py b/dbtemplates/management/commands/check_template_syntax.py index 3837e65..c315ad2 100644 --- a/dbtemplates/management/commands/check_template_syntax.py +++ b/dbtemplates/management/commands/check_template_syntax.py @@ -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") diff --git a/dbtemplates/management/commands/create_error_templates.py b/dbtemplates/management/commands/create_error_templates.py index 3c53d24..f7a78c9 100644 --- a/dbtemplates/management/commands/create_error_templates.py +++ b/dbtemplates/management/commands/create_error_templates.py @@ -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 + ) diff --git a/dbtemplates/management/commands/sync_templates.py b/dbtemplates/management/commands/sync_templates.py index 6ce7fdc..047fedb 100644 --- a/dbtemplates/management/commands/sync_templates.py +++ b/dbtemplates/management/commands/sync_templates.py @@ -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: diff --git a/dbtemplates/migrations/0001_initial.py b/dbtemplates/migrations/0001_initial.py index 7ac217f..b0e5dab 100644 --- a/dbtemplates/migrations/0001_initial.py +++ b/dbtemplates/migrations/0001_initial.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ("sites", "0001_initial"), ] diff --git a/dbtemplates/migrations/0002_alter_template_creation_date_and_more.py b/dbtemplates/migrations/0002_alter_template_creation_date_and_more.py index 61cb561..73d4a0d 100644 --- a/dbtemplates/migrations/0002_alter_template_creation_date_and_more.py +++ b/dbtemplates/migrations/0002_alter_template_creation_date_and_more.py @@ -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"), ), ] diff --git a/dbtemplates/models.py b/dbtemplates/models.py index e84ecd3..62f4a1c 100644 --- a/dbtemplates/models.py +++ b/dbtemplates/models.py @@ -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 diff --git a/dbtemplates/test_cases.py b/dbtemplates/test_cases.py index acd0cf1..0a2109d 100644 --- a/dbtemplates/test_cases.py +++ b/dbtemplates/test_cases.py @@ -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='

This is a header

') + t0 = Template.objects.create( + name="header.html", content="

This is a header

" + ) t0.populate() self.assertEqual(t0.content, "

This is a header

") - t0.populate(name='header.html') + t0.populate(name="header.html") self.assertEqual(t0.content, "

This is a header

") - 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() + ) diff --git a/dbtemplates/test_settings.py b/dbtemplates/test_settings.py index 275435d..d39673d 100644 --- a/dbtemplates/test_settings.py +++ b/dbtemplates/test_settings.py @@ -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", + ], + }, }, ] diff --git a/dbtemplates/utils/cache.py b/dbtemplates/utils/cache.py index 89039ab..11bd6ca 100644 --- a/dbtemplates/utils/cache.py +++ b/dbtemplates/utils/cache.py @@ -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 diff --git a/dbtemplates/utils/template.py b/dbtemplates/utils/template.py index cd82c36..e8d3be4 100644 --- a/dbtemplates/utils/template.py +++ b/dbtemplates/utils/template.py @@ -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): diff --git a/docs/conf.py b/docs/conf.py index 2055241..6b2422f 100644 --- a/docs/conf.py +++ b/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 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