Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Django 4.x #126

Merged
merged 29 commits into from
Aug 11, 2022
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
9e4a6f7
Django 4.x
mpasternak Jun 15, 2022
8901551
Merge branch 'master' of github.com:mpasternak/django-dbtemplates-iplweb
mpasternak Jun 15, 2022
2d622ee
Python 3.10
mpasternak Jun 15, 2022
e477561
Proper image path
mpasternak Jun 15, 2022
9f664ea
Django 4.x fix
mpasternak Jun 15, 2022
e1e11c4
Django 4.x fixes
mpasternak Jun 15, 2022
9dbdb95
Rename for PyPI release
mpasternak Jun 15, 2022
5281b74
Don't change basepython for flake8
mpasternak Jun 15, 2022
de4babc
Describe changes
mpasternak Jun 15, 2022
7ffc0fa
Don't build unversal wheel
mpasternak Jun 15, 2022
0130574
Min. Python version
mpasternak Jun 15, 2022
1a20742
Fix flake8 target on GitHub
mpasternak Jun 15, 2022
2e3f009
Merge branch 'master' into master
mpasternak Aug 7, 2022
f98fb8c
Min. supported Python version
mpasternak Aug 7, 2022
b138caf
Passing flake8
mpasternak Aug 7, 2022
2b50349
Remove unsupported Django versions
mpasternak Aug 9, 2022
a68caed
Revert unintentional typo
mpasternak Aug 9, 2022
6dd23d2
Proper links to CI badge
mpasternak Aug 9, 2022
e08a8d3
Document changes in 4.0 (unreleased)
mpasternak Aug 9, 2022
36fbb80
Update to Django 4.0 i18n style
mpasternak Aug 9, 2022
b6b0bf4
Django 4.0 i18n fixes
mpasternak Aug 9, 2022
98bc992
Remove trailing whitespace
mpasternak Aug 9, 2022
2c8dc82
Update tox.ini
mpasternak Aug 9, 2022
5a363db
Update setup.py
mpasternak Aug 10, 2022
45e216b
Remove compatibility wrapper
mpasternak Aug 10, 2022
6ca5398
Test all the supported versions
mpasternak Aug 10, 2022
f53244c
Merge branch 'master' of github.com:mpasternak/django-dbtemplates-iplweb
mpasternak Aug 10, 2022
fac9f6a
Mention dropping Django below 3.2
mpasternak Aug 10, 2022
fa72b27
Flake8
mpasternak Aug 10, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ django-dbtemplates
:target: https://jazzband.co/

.. image:: https://github.com/jazzband/django-dbtemplates/workflows/Test/badge.svg
:target: https://github.com/jazzband/django-dbtemplates/actions
:alt: GitHub Actions
:target: https://github.com/jazzband/django-dbtemplates/actions

.. image:: https://codecov.io/github/jazzband/django-dbtemplates/coverage.svg?branch=master
:alt: Codecov
Expand Down
30 changes: 20 additions & 10 deletions dbtemplates/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,27 @@
from django import forms
from django.contrib import admin
from django.core.exceptions import ImproperlyConfigured
from django.utils.translation import ungettext, ugettext_lazy as _
try:
# Django 4.0
from django.utils.translation import gettext_lazy as _
from django.utils.translation import ngettext
except ImportError:
# Before Django 4.0
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ungettext as ngettext

from django.utils.safestring import mark_safe

from dbtemplates.conf import settings
from dbtemplates.models import (Template, remove_cached_template,
add_template_to_cache)
from dbtemplates.models import Template, add_template_to_cache, remove_cached_template
from dbtemplates.utils.template import check_template_syntax

# 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
from reversion_compare.admin import CompareVersionAdmin \
as TemplateModelAdmin
elif settings.DBTEMPLATES_USE_REVERSION:
from reversion.admin import VersionAdmin as TemplateModelAdmin
else:
Expand All @@ -30,7 +38,8 @@ class CodeMirrorTextArea(forms.Textarea):
class Media:
css = dict(screen=[posixpath.join(
settings.DBTEMPLATES_MEDIA_PREFIX, 'css/editor.css')])
js = [posixpath.join(settings.DBTEMPLATES_MEDIA_PREFIX, 'js/codemirror.js')]
js = [posixpath.join(settings.DBTEMPLATES_MEDIA_PREFIX,
'js/codemirror.js')]

def render(self, name, value, attrs=None, renderer=None):
result = []
Expand Down Expand Up @@ -119,7 +128,7 @@ def invalidate_cache(self, request, queryset):
for template in queryset:
remove_cached_template(template)
count = queryset.count()
message = ungettext(
message = ngettext(
"Cache of one template successfully invalidated.",
"Cache of %(count)d templates successfully invalidated.",
count)
Expand All @@ -131,7 +140,7 @@ def repopulate_cache(self, request, queryset):
for template in queryset:
add_template_to_cache(template)
count = queryset.count()
message = ungettext(
message = ngettext(
"Cache successfully repopulated with one template.",
"Cache successfully repopulated with %(count)d templates.",
count)
Expand All @@ -147,15 +156,16 @@ def check_syntax(self, request, queryset):
errors.append(f'{template.name}: {error}')
if errors:
count = len(errors)
message = ungettext(
message = ngettext(
"Template syntax check FAILED for %(names)s.",
"Template syntax check FAILED for %(count)d templates: %(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 = ungettext(
message = ngettext(
"Template syntax OK.",
"Template syntax OK for %(count)d templates.", count)
self.message_user(request, message % {'count': count})
Expand Down
5 changes: 4 additions & 1 deletion dbtemplates/apps.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
try:
from django.utils.translation import ugettext_lazy as _
except ImportError:
from django.utils.translation import gettext_lazy as _


class DBTemplatesConfig(AppConfig):
Expand Down
4 changes: 2 additions & 2 deletions dbtemplates/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ def configure_use_reversion(self, 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 "
raise ImproperlyConfigured("Please add 'reversion_compare' to your"
" INSTALLED_APPS setting to make "
"use of it in dbtemplates.")
return value

Expand Down
7 changes: 4 additions & 3 deletions dbtemplates/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ 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):
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}'
Expand Down Expand Up @@ -73,11 +74,11 @@ def _load_template_source(self, template_name, template_dirs=None):

try:
return self._load_and_store_template(template_name, cache_key,
site, sites__in=[site.id])
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)
site, sites__isnull=True)
except (Template.MultipleObjectsReturned, Template.DoesNotExist):
pass

Expand Down
126 changes: 80 additions & 46 deletions dbtemplates/management/commands/sync_templates.py
Original file line number Diff line number Diff line change
@@ -1,64 +1,86 @@
import os
from django.contrib.sites.models import Site
from django.core.management.base import CommandError, BaseCommand
from django.template.utils import get_app_template_dirs
from django.template.loader import _engine_list

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')
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')
app_template_dirs = get_app_template_dirs("templates")


class Command(BaseCommand):
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",
"-e",
"--ext",
dest="ext",
action="store",
default="html",
help="extension of the files you want to "
"sync with the database [default: %(default)s]")
"sync with the database [default: %(default)s]",
)
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",
)
parser.add_argument(
"-o", "--overwrite",
action="store", dest="overwrite", default='0',
"-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")
"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,
"-a",
"--app-first",
action="store_true",
dest="app_first",
default=False,
help="look for templates in applications "
"directories before project templates")
"directories before project templates",
)
parser.add_argument(
"-d", "--delete",
action="store_true", dest="delete", default=False,
help="Delete templates after syncing")
"-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')
extension = options.get("ext")
force = options.get("force")
overwrite = options.get("overwrite")
app_first = options.get("app_first")
delete = options.get("delete")

if not extension.startswith("."):
extension = f".{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")
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
Expand All @@ -68,11 +90,14 @@ def handle(self, **options):

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('/'):
if name.startswith("/"):
name = name[1:]
try:
t = Template.on_site.get(name__exact=name)
Expand All @@ -81,27 +106,35 @@ def handle(self, **options):
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:
" (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())
t.save()
t.sites.add(site)
else:
while 1:
while True:
if overwrite == ALWAYS_ASK:
confirm = input(
_i = (
"\n%(template)s exists in the database.\n"
"(1) Overwrite %(template)s with '%(path)s'\n"
"(2) Overwrite '%(path)s' with %(template)s\n"
"Type 1 or 2 or press <Enter> to skip: " %
{'template': t.__repr__(), 'path': path})
"(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 in (
"",
FILES_TO_DATABASE,
DATABASE_TO_FILES,
):
if confirm == FILES_TO_DATABASE:
with open(path, encoding='utf-8') as f:
with open(path, encoding="utf-8") as f:
t.content = f.read()
t.save()
t.sites.add(site)
Expand All @@ -110,9 +143,10 @@ def handle(self, **options):
os.remove(path)
except OSError:
raise CommandError(
f"Couldn't delete {path}")
f"Couldn't delete {path}"
)
elif confirm == DATABASE_TO_FILES:
with open(path, 'w', encoding='utf-8') as f:
with open(path, "w", encoding="utf-8") as f: # noqa
f.write(t.content)
if delete:
t.delete()
Expand Down
Loading