From 555c30d93285b259540324eea9faf6ab01a54dfe Mon Sep 17 00:00:00 2001 From: Bruno Alla Date: Thu, 13 Mar 2025 21:09:23 +0000 Subject: [PATCH] Introduce app settings Following the blueprint from [this blog post](https://overtag.dk/v2/blog/a-settings-pattern-for-reusable-django-apps/). Refactor DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH to use the new setting namespace and document it. --- django_celery_results/conf.py | 41 +++++++++++++++++++ .../migrations/0001_initial.py | 9 ++-- .../migrations/0004_auto_20190516_0412.py | 14 ++----- .../migrations/0008_chordcounter.py | 9 ++-- .../migrations/0009_groupresult.py | 27 +++--------- django_celery_results/models.py | 26 +++--------- docs/configuration.rst | 15 +++++++ docs/index.rst | 1 + setup.cfg | 2 +- 9 files changed, 80 insertions(+), 64 deletions(-) create mode 100644 django_celery_results/conf.py create mode 100644 docs/configuration.rst diff --git a/django_celery_results/conf.py b/django_celery_results/conf.py new file mode 100644 index 00000000..11ac0e9a --- /dev/null +++ b/django_celery_results/conf.py @@ -0,0 +1,41 @@ +"""Application settings.""" +from dataclasses import dataclass +from typing import Any + +from django.conf import settings as django_settings + +# All attributes accessed with this prefix are possible +# to overwrite through django.conf.settings. +SETTINGS_PREFIX = "DJANGO_CELERY_RESULTS_" + + +@dataclass(frozen=True) +class AppSettings: + """Proxy class to encapsulate all the app settings. + + This instance should be accessed via the singleton + ``django_celery_results.conf.app_settings``. + + You shouldn't have to set any of these yourself, the class checks a Django + settings with the same name and use these if defined, defaulting to the + values documented here. + """ + + DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH: int = 255 + + def __getattribute__(self, __name: str) -> Any: + """Check if a Django project settings should override the app default. + + In order to avoid returning any random properties of the Django + settings, we first inspect the prefix. + """ + if ( + __name.startswith(SETTINGS_PREFIX) + and hasattr(django_settings, __name) + ): + return getattr(django_settings, __name) + + return super().__getattribute__(__name) + + +app_settings = AppSettings() diff --git a/django_celery_results/migrations/0001_initial.py b/django_celery_results/migrations/0001_initial.py index 91599f96..e0593024 100644 --- a/django_celery_results/migrations/0001_initial.py +++ b/django_celery_results/migrations/0001_initial.py @@ -1,6 +1,7 @@ -from django.conf import settings from django.db import migrations, models +from django_celery_results.conf import app_settings + class Migration(migrations.Migration): @@ -18,11 +19,7 @@ class Migration(migrations.Migration): serialize=False, verbose_name='ID')), ('task_id', models.CharField( - max_length=getattr( - settings, - 'DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH', - 255 - ), + max_length=app_settings.DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH, # noqa: E501 unique=True, verbose_name='task id' )), diff --git a/django_celery_results/migrations/0004_auto_20190516_0412.py b/django_celery_results/migrations/0004_auto_20190516_0412.py index a52375e6..1aeba620 100644 --- a/django_celery_results/migrations/0004_auto_20190516_0412.py +++ b/django_celery_results/migrations/0004_auto_20190516_0412.py @@ -7,6 +7,8 @@ from django.conf import settings from django.db import migrations, models +from django_celery_results.conf import app_settings + class Migration(migrations.Migration): @@ -61,11 +63,7 @@ class Migration(migrations.Migration): field=models.CharField( db_index=True, help_text='Celery ID for the Task that was run', - max_length=getattr( - settings, - 'DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH', - 255 - ), + max_length=app_settings.DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH, unique=True, verbose_name='Task ID' ), @@ -81,11 +79,7 @@ class Migration(migrations.Migration): field=models.CharField( db_index=True, help_text='Name of the Task which was run', - max_length=getattr( - settings, - 'DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH', - 255 - ), + max_length=app_settings.DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH, null=True, verbose_name='Task Name'), ), diff --git a/django_celery_results/migrations/0008_chordcounter.py b/django_celery_results/migrations/0008_chordcounter.py index 0e64adfe..9866e8e3 100644 --- a/django_celery_results/migrations/0008_chordcounter.py +++ b/django_celery_results/migrations/0008_chordcounter.py @@ -1,8 +1,9 @@ # Generated by Django 3.0.6 on 2020-05-12 12:05 -from django.conf import settings from django.db import migrations, models +from django_celery_results.conf import app_settings + class Migration(migrations.Migration): @@ -22,11 +23,7 @@ class Migration(migrations.Migration): ('group_id', models.CharField( db_index=True, help_text='Celery ID for the Chord header group', - max_length=getattr( - settings, - 'DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH', - 255 - ), + max_length=app_settings.DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH, # noqa: E501 unique=True, verbose_name='Group ID')), ('sub_tasks', models.TextField( diff --git a/django_celery_results/migrations/0009_groupresult.py b/django_celery_results/migrations/0009_groupresult.py index 7c14608c..ea150b5f 100644 --- a/django_celery_results/migrations/0009_groupresult.py +++ b/django_celery_results/migrations/0009_groupresult.py @@ -1,7 +1,8 @@ # Generated by Django 3.2 on 2021-04-19 14:55 -from django.conf import settings from django.db import migrations, models +from django_celery_results.conf import app_settings + class FakeAddIndex(migrations.AddIndex): """Fake AddIndex to correct for duplicate index @@ -35,11 +36,7 @@ class Migration(migrations.Migration): verbose_name='ID')), ('group_id', models.CharField( help_text='Celery ID for the Group that was run', - max_length=getattr( - settings, - 'DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH', - 255 - ), + max_length=app_settings.DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH, # noqa: E501 unique=True, verbose_name='Group ID')), ('date_created', models.DateTimeField( @@ -81,11 +78,7 @@ class Migration(migrations.Migration): name='group_id', field=models.CharField( help_text='Celery ID for the Chord header group', - max_length=getattr( - settings, - 'DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH', - 255 - ), + max_length=app_settings.DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH, # noqa: E501 unique=True, verbose_name='Group ID'), ), @@ -128,11 +121,7 @@ class Migration(migrations.Migration): name='task_id', field=models.CharField( help_text='Celery ID for the Task that was run', - max_length=getattr( - settings, - 'DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH', - 255 - ), + max_length=app_settings.DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH, # noqa: E501 unique=True, verbose_name='Task ID'), ), @@ -141,11 +130,7 @@ class Migration(migrations.Migration): name='task_name', field=models.CharField( help_text='Name of the Task which was run', - max_length=getattr( - settings, - 'DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH', - 255 - ), + max_length=app_settings.DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH, # noqa: E501 null=True, verbose_name='Task Name'), ), diff --git a/django_celery_results/models.py b/django_celery_results/models.py index b472a5af..b6416603 100644 --- a/django_celery_results/models.py +++ b/django_celery_results/models.py @@ -5,11 +5,11 @@ from celery import states from celery.result import GroupResult as CeleryGroupResult from celery.result import result_from_tuple -from django.conf import settings from django.db import models from django.utils.translation import gettext_lazy as _ from . import managers +from .conf import app_settings ALL_STATES = sorted(states.ALL_STATES) TASK_STATE_CHOICES = sorted(zip(ALL_STATES, ALL_STATES)) @@ -19,11 +19,7 @@ class TaskResult(models.Model): """Task result/status.""" task_id = models.CharField( - max_length=getattr( - settings, - 'DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH', - 255 - ), + max_length=app_settings.DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH, unique=True, verbose_name=_('Task ID'), help_text=_('Celery ID for the Task that was run')) @@ -32,11 +28,8 @@ class TaskResult(models.Model): verbose_name=_('Periodic Task Name'), help_text=_('Name of the Periodic Task which was run')) task_name = models.CharField( - null=True, max_length=getattr( - settings, - 'DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH', - 255 - ), + null=True, + max_length=app_settings.DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH, verbose_name=_('Task Name'), help_text=_('Name of the Task which was run')) task_args = models.TextField( @@ -140,10 +133,7 @@ class ChordCounter(models.Model): """Chord synchronisation.""" group_id = models.CharField( - max_length=getattr( - settings, - "DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH", - 255), + max_length=app_settings.DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH, unique=True, verbose_name=_("Group ID"), help_text=_("Celery ID for the Chord header group"), @@ -181,11 +171,7 @@ class GroupResult(models.Model): """Task Group result/status.""" group_id = models.CharField( - max_length=getattr( - settings, - "DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH", - 255 - ), + max_length=app_settings.DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH, unique=True, verbose_name=_("Group ID"), help_text=_("Celery ID for the Group that was run"), diff --git a/docs/configuration.rst b/docs/configuration.rst new file mode 100644 index 00000000..d976b81d --- /dev/null +++ b/docs/configuration.rst @@ -0,0 +1,15 @@ +Configuration +============= + +These are the available settings that can be configured in your Django +project's settings module by defining a setting with the same name. + +.. _settings-task_id_max_length: + +* ``DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH`` (Default: ``255``) + + The max length, as an integer, of the ``task_id`` and ``task_name`` + fields on the ``TaskResult`` model. Defaults to 255. + + Also used for the max length of the ``group_id`` fields on the + ``GroupResult`` and ``ChordCounter`` models. diff --git a/docs/index.rst b/docs/index.rst index ad00baf2..e203fac2 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -12,6 +12,7 @@ Contents getting_started injecting_metadata + configuration copyright .. toctree:: diff --git a/setup.cfg b/setup.cfg index 26f1ac65..bef5e063 100644 --- a/setup.cfg +++ b/setup.cfg @@ -9,7 +9,7 @@ markers = [flake8] # classes can be lowercase, arguments and variables can be uppercase # whenever it makes the code more readable. -ignore = N806, N802, N801, N803 +ignore = N806, N802, N801, N803, W503 [pep257] convention=google