diff --git a/.coveragerc b/.coveragerc index 1fa4289..3ae90e7 100644 --- a/.coveragerc +++ b/.coveragerc @@ -3,4 +3,4 @@ source = dbtemplates branch = 1 [report] -omit = *tests*,*migrations* +omit = *tests*,*/migrations/*,test_* diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8eb2414..7150ea4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,7 +33,7 @@ jobs: - name: Upload packages to Jazzband if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') - uses: pypa/gh-action-pypi-publish@master + uses: pypa/gh-action-pypi-publish@release/v1 with: user: jazzband password: ${{ secrets.JAZZBAND_RELEASE_KEY }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d6f9e0e..4151364 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,7 +9,7 @@ jobs: fail-fast: false max-parallel: 5 matrix: - python-version: ['3.7', '3.8', '3.9', '3.10', '3.11-dev'] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.13'] steps: - uses: actions/checkout@v3 diff --git a/dbtemplates/__init__.py b/dbtemplates/__init__.py index 23b4a18..fe02d11 100644 --- a/dbtemplates/__init__.py +++ b/dbtemplates/__init__.py @@ -1,10 +1,3 @@ -from pkg_resources import get_distribution, DistributionNotFound +import importlib.metadata -try: - __version__ = get_distribution("django-dbtemplates").version -except DistributionNotFound: - # package is not installed - __version__ = None - - -default_app_config = 'dbtemplates.apps.DBTemplatesConfig' +__version__ = importlib.metadata.version("django-dbtemplates") diff --git a/dbtemplates/admin.py b/dbtemplates/admin.py index 1c9095f..f6d65af 100644 --- a/dbtemplates/admin.py +++ b/dbtemplates/admin.py @@ -2,15 +2,8 @@ import posixpath from django import forms from django.contrib import admin from django.core.exceptions import ImproperlyConfigured -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.translation import gettext_lazy as _ +from django.utils.translation import ngettext from django.utils.safestring import mark_safe from dbtemplates.conf import settings @@ -104,6 +97,7 @@ class TemplateAdminForm(forms.ModelForm): class TemplateAdmin(TemplateModelAdmin): form = TemplateAdminForm + readonly_fields = ['creation_date', 'last_changed'] fieldsets = ( (None, { 'fields': ('name', 'content'), diff --git a/dbtemplates/apps.py b/dbtemplates/apps.py index 21141b3..9f75273 100644 --- a/dbtemplates/apps.py +++ b/dbtemplates/apps.py @@ -1,10 +1,9 @@ from django.apps import AppConfig -try: - from django.utils.translation import ugettext_lazy as _ -except ImportError: - from django.utils.translation import gettext_lazy as _ +from django.utils.translation import gettext_lazy as _ class DBTemplatesConfig(AppConfig): name = 'dbtemplates' verbose_name = _('Database templates') + + default_auto_field = 'django.db.models.AutoField' diff --git a/dbtemplates/migrations/0002_alter_template_creation_date_and_more.py b/dbtemplates/migrations/0002_alter_template_creation_date_and_more.py new file mode 100644 index 0000000..61cb561 --- /dev/null +++ b/dbtemplates/migrations/0002_alter_template_creation_date_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 5.1 on 2025-05-26 19:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dbtemplates', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='template', + name='creation_date', + field=models.DateTimeField(auto_now_add=True, verbose_name='creation date'), + ), + migrations.AlterField( + model_name='template', + name='last_changed', + field=models.DateTimeField(auto_now=True, verbose_name='last changed'), + ), + ] diff --git a/dbtemplates/models.py b/dbtemplates/models.py index f846b2b..aa87dcb 100644 --- a/dbtemplates/models.py +++ b/dbtemplates/models.py @@ -1,20 +1,16 @@ from dbtemplates.conf import settings -from dbtemplates.utils.cache import (add_template_to_cache, - remove_cached_template) +from dbtemplates.utils.cache import ( + add_template_to_cache, + remove_cached_template, +) from dbtemplates.utils.template import get_template_source + from django.contrib.sites.managers import CurrentSiteManager from django.contrib.sites.models import Site from django.db import models from django.db.models import signals from django.template import TemplateDoesNotExist -try: - # Django >= 4.0 - from django.utils.translation import gettext_lazy as _ -except ImportError: - # Django 3.2 - from django.utils.translation import ugettext_lazy as _ - -from django.utils.timezone import now +from django.utils.translation import gettext_lazy as _ class Template(models.Model): @@ -22,15 +18,15 @@ 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'), - default=now) - last_changed = models.DateTimeField(_('last changed'), - default=now) + 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') @@ -59,7 +55,6 @@ class Template(models.Model): pass def save(self, *args, **kwargs): - self.last_changed = now() # If content is empty look for a template with the given name and # populate the template instance with its content. if settings.DBTEMPLATES_AUTO_POPULATE_CONTENT and not self.content: diff --git a/docs/changelog.txt b/docs/changelog.txt index 03a3c16..33b3496 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -1,7 +1,20 @@ Changelog ========= -v4.0 (unreleased) +v5.0 (unreleased) +----------------- + +.. warning:: + + This is a backwards-incompatible release! + +* Dropped support for Python 3.7 and Django < 4.2. + +* Added support for Python 3.11, 3.12, 3.13. + +* Django 5.x support + +v4.0 (2022-09-3) ----------------- .. warning:: diff --git a/docs/overview.txt b/docs/overview.txt index 99e430e..8bcb816 100644 --- a/docs/overview.txt +++ b/docs/overview.txt @@ -3,8 +3,7 @@ Setup 1. Get the source from the `Git repository`_ or install it from the Python Package Index by running ``pip install django-dbtemplates``. -2. Follow the instructions in the INSTALL file -3. Edit the settings.py of your Django site: +2. Edit the settings.py of your Django site: * Add ``dbtemplates`` to the ``INSTALLED_APPS`` setting @@ -61,8 +60,8 @@ Setup from the database to be used to override templates in other locations, put ``dbtemplates.loader.Loader`` at the beginning of ``loaders``. -4. Sync your database ``python manage.py migrate`` -5. Restart your Django server +3. Sync your database ``python manage.py migrate`` +4. Restart your Django server .. _Git repository: https://github.com/jazzband/django-dbtemplates/ diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..32be57b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,51 @@ +[build-system] +requires = [ + "setuptools>=61.2", + "setuptools_scm", +] +build-backend = "setuptools.build_meta" + +[project] +name = "django-dbtemplates" +authors = [{name = "Jannis Leidel", email = "jannis@leidel.info"}] +description = "Template loader for templates stored in the database" +readme = "README.rst" +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Environment :: Web Environment", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Framework :: Django", +] +requires-python = ">=3.8" +dependencies = ["django-appconf >= 0.4"] +dynamic = ["version"] + +[project.urls] +Documentation = "https://django-dbtemplates.readthedocs.io/" +Changelog = "https://django-dbtemplates.readthedocs.io/en/latest/changelog.html" +Source = "https://github.com/jazzband/django-dbtemplates" + +[tool.setuptools] +zip-safe = false +include-package-data = false + +[tool.setuptools.packages] +find = {namespaces = false} + +[tool.setuptools.package-data] +dbtemplates = [ + "locale/*/LC_MESSAGES/*", + "static/dbtemplates/css/*.css", + "static/dbtemplates/js/*.js", +] diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index a5516f1..0000000 --- a/setup.cfg +++ /dev/null @@ -1,4 +0,0 @@ -[build_sphinx] -source-dir = docs/ -build-dir = docs/_build -all_files = 1 diff --git a/setup.py b/setup.py deleted file mode 100644 index 5a43497..0000000 --- a/setup.py +++ /dev/null @@ -1,48 +0,0 @@ -import os -import io -from setuptools import setup, find_packages - - -def read(*parts): - filename = os.path.join(os.path.dirname(__file__), *parts) - with open(filename, encoding="utf-8") as fp: - return fp.read() - - -setup( - name="django-dbtemplates", - use_scm_version={"version_scheme": "post-release"}, - setup_requires=["setuptools_scm"], - description="Template loader for templates stored in the database", - long_description=read("README.rst"), - author="Jannis Leidel", - author_email="jannis@leidel.info", - url="https://django-dbtemplates.readthedocs.io/", - packages=find_packages(), - zip_safe=False, - package_data={ - "dbtemplates": [ - "locale/*/LC_MESSAGES/*", - "static/dbtemplates/css/*.css", - "static/dbtemplates/js/*.js", - ], - }, - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Environment :: Web Environment", - "Intended Audience :: Developers", - "License :: OSI Approved :: BSD License", - "Operating System :: OS Independent", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Framework :: Django", - ], - python_requires=">=3.7", - install_requires=["django-appconf >= 0.4"], -) - diff --git a/tox.ini b/tox.ini index d0178be..0b09a40 100644 --- a/tox.ini +++ b/tox.ini @@ -1,41 +1,53 @@ [tox] -skipsdist = True -usedevelop = True -minversion = 1.8 +minversion = 4.0 envlist = flake8 - py3{7,8,9,10,11}-dj32 - py3{8,9,10,11}-dj{40,41,main} + py3{8,9,10,11,12}-dj42 + py3{10,11,12}-dj{50} + py3{10,11,12,13}-dj{51,52} + py3{12,13}-dj{main} + coverage [gh-actions] python = - 3.7: py37 3.8: py38 3.9: py39 3.10: py310 3.10: py310, flake8 3.11: py311 + 3.12: py312 + 3.13: py313 [testenv] +skipsdist = true +package = editable basepython = - py37: python3.7 py38: python3.8 py39: python3.9 py310: python3.10 py311: python3.11 -usedevelop = true + py312: python3.12 + py313: python3.13 setenv = DJANGO_SETTINGS_MODULE = dbtemplates.test_settings deps = -r requirements/tests.txt - dj32: Django<3.3 - dj40: Django<4.1 - dj41: Django<4.2 + dj42: Django>=4.2,<4.3 + dj50: Django>=5.0,<5.1 + dj51: Django>=5.1,<5.2 + dj52: Django>=5.2,<5.3 djmain: https://github.com/django/django/archive/main.tar.gz#egg=django commands = python --version - coverage run {envbindir}/django-admin test -v2 {posargs:dbtemplates} + python -c "import django ; print(django.VERSION)" + coverage run --branch --parallel-mode {envbindir}/django-admin test -v2 {posargs:dbtemplates} + +[testenv:coverage] +basepython = python3.10 +deps = coverage +commands = + coverage combine coverage report coverage xml