{"id":14972872,"url":"https://github.com/kezabelle/django-stagesetting","last_synced_at":"2025-10-26T20:32:11.950Z","repository":{"id":35209465,"uuid":"39468404","full_name":"kezabelle/django-stagesetting","owner":"kezabelle","description":"dynamic site settings, based on Django Forms, and optionally the Django Admin","archived":false,"fork":false,"pushed_at":"2018-09-14T11:00:05.000Z","size":126,"stargazers_count":5,"open_issues_count":5,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-02-01T00:23:33.849Z","etag":null,"topics":["django","django-admin","django-application","django-middleware","django-settings"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kezabelle.png","metadata":{"files":{"readme":"README.rst","changelog":"CHANGELOG","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-07-21T20:31:46.000Z","updated_at":"2020-06-15T14:26:28.000Z","dependencies_parsed_at":"2022-09-06T14:02:11.126Z","dependency_job_id":null,"html_url":"https://github.com/kezabelle/django-stagesetting","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kezabelle%2Fdjango-stagesetting","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kezabelle%2Fdjango-stagesetting/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kezabelle%2Fdjango-stagesetting/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kezabelle%2Fdjango-stagesetting/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kezabelle","download_url":"https://codeload.github.com/kezabelle/django-stagesetting/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238397210,"owners_count":19465134,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django","django-admin","django-application","django-middleware","django-settings"],"created_at":"2024-09-24T13:47:40.245Z","updated_at":"2025-10-26T20:32:06.621Z","avatar_url":"https://github.com/kezabelle.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"django-stagesetting 0.5.0\n=========================\n\nAn application for managing site configuration through normal `Django`_ forms,\nand thus through the `admin site`_.\n\n.. |travis_stable| image:: https://travis-ci.org/kezabelle/django-stagesetting.svg?branch=0.5.0\n  :target: https://travis-ci.org/kezabelle/django-stagesetting\n\n.. |travis_master| image:: https://travis-ci.org/kezabelle/django-stagesetting.svg?branch=master\n  :target: https://travis-ci.org/kezabelle/django-stagesetting\n\n==============  ======\nRelease         Status\n==============  ======\nstable (0.5.0)  |travis_stable|\nmaster          |travis_master|\n==============  ======\n\nPre-requisites\n--------------\n\nThe following versions are tested:\n\n* Python 2.7, or 3.3+\n* `Django`_ 1.7+\n\nInstallation\n------------\n\nFirst up, you need to install it  (via `pip`_ as usual)::\n\n    pip install django-stagesetting==0.5.0\n\nOnce that's downloaded, add the package to your ``INSTALLED_APPS``\nin your settings::\n\n    INSTALLED_APPS = (\n        # ...\n        'stagesetting',\n        # ...\n    )\n\ndo a migrate::\n\n    python manage.py migrate stagesetting\n\nAdd a ``STAGESETTINGS`` dictionary to your project's settings::\n\n    STAGESETTINGS = {\n        'SETTING_NAME': '...',\n        'ANOTHER_SETTING_NAME': '...',\n    }\n\nThe setting collection name is the dictionary key, so must be unique.\n\nWriting settings\n^^^^^^^^^^^^^^^^\nSettings may be created in a number of ways, the simplest of which is to\nprovide a ``dictionary`` as the value::\n\n    STAGESETTINGS = {\n        'MY_SETTING': {\n            'an_example-datetime': datetime.today(),\n            'a_date': date.today(),\n            'time_now': time(4, 23),\n            'boolean_field': False,\n            'plain_text': 'char field',\n            'decimal': Decimal('3.25'),\n            'float': 2.3,\n        }\n    }\n\nwhere possible, this will auto-generate a Form class for you, choosing sensible\ndefaults for the field variants where possible.\n\nThe other option is for the value to be a ``list`` or a ``tuple``, where\nthe *first item* represents a form (either a ``dictionary`` as above, **OR**\nthe ``dotted.path.to.a.Form.Class`` if you need custom validation) and the\n*second, optional item* is the default data. The following should all be valid::\n\n    STAGESETTINGS = {\n        'AUTO_GENERATED': [{\n            'datetime': datetime.today(),\n        }],\n        'IMPORT_A_FORM': ['myapp.forms.MyForm'],\n        'IMPORT_WITH_DEFAULT': ['myapp.forms.MyForm', {'default': 'data'}],\n        'AUTO_GENERATED_WITH_OTHER_DEFAULTS': [{\n            'datetime': datetime.today(),\n        }, {'default': 'data'}],\n    }\n\nA simple configuration form (for the ``dotted.path.Format``) might look like::\n\n    from django.core.exceptions import ValidationError\n    from django.forms import Form, DateField\n\n    class DateForm(Form):\n        start = DateField()\n        end = DateField()\n\n        def clean(self):\n            cd = self.cleaned_data\n            if 'start' in cd and 'end' in cd and cd['start'] \u003e cd['end']:\n                raise ValidationError(\"Start date cannot be after end date\")\n            return cd\n\nAs you can see, it really is just a normal `Form`_. Internally, this form's\n``cleaned_data`` will be converted into `JSON`_ before being saved to the\ndatabase.\nIt will get re-converted to proper Python values when pulled out\nof the database, by going through the given `Form`_ class's validation again,\nincluding converting to rich values like model instances.\n\n\nPython types which can be detected\n**********************************\n\nWhen detecting a dictionary as the value and auto-generating a form, the\nfollowing translations will be applied:\n\n- ``None`` becomes `NullBooleanField`_\n- ``datetime.datetime`` becomes `DateTimeField`_\n- ``datetime.date`` becomes `DateField`_\n- ``datetime.time`` becomes `TimeField`_\n- ``datetime.timedelta`` becomes `DurationField`_\n- ``decimal.Decimal`` becomes `DecimalField`_\n- ``float`` becomes `FloatField`_\n- ``True`` or ``False`` become `BooleanField`_\n- ``int`` becomes `IntegerField`_\n- ``uuid.UUID`` becomes `UUIDField`_ or `RegexField`_, depending on the `Django`_ version\n- ``list`` and ``tuple`` become `MultipleChoiceField`_\n- ``collections.OrderedDict``, ``set``, ``frozenset``, and ``dict`` become `ChoiceField`_\n- ``models.Model`` instances become `ModelChoiceField`_\n- ``models.QuerySet`` becomes `ModelMultipleChoiceField`_\n- strings become one of the following, depending on what checks they pass:\n\n  - `GenericIPAddressField`_\n  - `URLField`_\n  - `EmailField`_\n  - `SlugField`_\n  - `CharField`_\n  - `IntegerField`_\n  - `DecimalField`_\n  - `UUIDField`_ (or `RegexField`_, depending on the `Django`_ version)\n  - `DateTimeField`_\n  - `DateField`_\n  - `TimeField`_\n- Some strings are **really** special, and will instead turn into one of the following:\n\n  - if the string == ``STATIC_URL`` or ``STATICFILES_STORAGE`` the field will be\n    a `ChoiceField`_ whose options are all the files found by the\n    project's ``STATICFILES_FINDERS``.\n  - if the string == ``MEDIA_URL``or ``DEFAULT_FILE_STORAGE`` the field will be\n    a `ChoiceField`_ whose options are all the files found by\n    ``DEFAULT_FILE_STORAGE``.\n  - if the string *starts with* ``STATIC_URL`` it will be the same as using\n    the ``STATIC_URL`` generated field, but is a regular expression for filtering\n    to only certain files (i.e. ``/static/.*\\.css$`` would find only css files)\n  - if the string *starts with* ``MEDIA_URL`` it will be the same as above,\n    but for files found in ``DEFAULT_FILE_STORAGE``.\n  - if a string looks like it contains HTML, it will try to use `django-bleach`_\n    for sanitisation, and one of `django-ckeditor`_, `django-tinymce`_,\n    `django-markdown`_, `django-pagedown`_, or `django-epiceditor`_ for an\n    appropriate widget.\n\nUsage in code\n-------------\n\nThe best way to access the settings in your views is to include\n``stagesetting.middleware.ApplyRuntimeSettings`` in your ``MIDDLEWARE_CLASSES``\nwhich will ensure there is a ``request.stagesettings`` variable which can be\nused like so::\n\n    def myview(request):\n        how_many_form_data = request.stagesetting.LIST_PER_PAGE\n        allow_empty_form_data = request.stagesetting['ALLOW_EMPTY']\n\neach setting will be a dictionary of the `Form`_ values, either the default ones\nor those changed in the database.\n\nUsage in templates\n------------------\n\nIf you've already got ``request`` in your template, obviously you can continue\nto use ``request.stagesettings`` if the middleware is wired up.\n\nIf you don't have request, or you're not using the middleware,\n``stagesetting.context_processors.runtime_settings`` provides a ``STAGESETTING``\ntemplate variable which contains the exact same data.\n\nFinally, if not using the middleware nor the context processor, there is a\ntemplate tag available as a last resort. It's usage is::\n\n    {% load stagesetting %}\n    {% stagesetting as NEW_CONTEXT_VARIABLE %}\n    {{ NEW_CONTEXT_VARIABLE.SETTING_NAME.fieldname }}\n\n\nUsage outside of a request\n--------------------------\n\nIf you don't have the middleware, or are in a part of the code which doesn't\nhave a ``request``, you can use the wrapper object directly::\n\n    from stagesetting.models import RuntimeSettingWrapper\n    def my_signal_handler(sender, instance, **kwargs):\n        live_settings = RuntimeSettingWrapper()\n        data = live_settings.LIST_PER_PAGE\n\nTry to keep a single ``RuntimeSettingWrapper`` around for as long as possible,\nrather than creating a new instance everywhere, as the object must fetch\nthe available settings from the database the first time it needs them. It\ncaches them for it's lifetime thereafter.\n\nAlternatives\n------------\n\nOther apps I know of that achieve similar things, or overlap in some obvious\nway. I won't judge you for using them, and I can't promise this is better.\nTo the victor, the spoils of maintenance!\n\n- `django-constance`_ is similar\n\n  - uses ``pickle`` to store an arbitrary python value; ``stagesetting`` only\n    stores stuff it can put into JSON and relies on `Django`_ `Forms`_ to inflate\n    the JSON back into python values.\n  - Has both database and redis backends; ``stagesetting`` only supports\n    the database, though it will only do one query most of the time.\n    \n- `django-dynamic-preferences`_ by the look of it.\n- `django-solo`_ as well.\n- `django-djconfig`_ looks similar in principle, insofar as it uses forms?\n- `django-aboutconfig`_ maybe?\n- `django-modelsettings`_ looks pretty similar - *define Django application settings with Django ORM models and edit them in the admin area.*\n\nIf you think GitHub popularity is an indication of usage and battle-tested \nproduction-readiness, then any of the above are certainly worth considering, \nbeing much more noticed than this, my attempt.\n\n.. _Django: https://docs.djangoproject.com/en/stable/\n.. _admin site: https://docs.djangoproject.com/en/stable/ref/contrib/admin/\n.. _contrib.admin: https://docs.djangoproject.com/en/stable/ref/contrib/admin/\n.. _Form: https://docs.djangoproject.com/en/stable/topics/forms/\n.. _Forms: https://docs.djangoproject.com/en/stable/topics/forms/\n.. _JSON: http://json.org/\n.. _pip: https://pip.pypa.io/en/stable/\n.. _pytest: http://pytest.org/latest/\n.. _BooleanField: https://docs.djangoproject.com/en/stable/ref/forms/fields/#booleanfield\n.. _CharField: https://docs.djangoproject.com/en/stable/ref/forms/fields/#charfield\n.. _RegexField: https://docs.djangoproject.com/en/stable/ref/forms/fields/#regexfield\n.. _ChoiceField: https://docs.djangoproject.com/en/stable/ref/forms/fields/#choicefield\n.. _DateField: https://docs.djangoproject.com/en/stable/ref/forms/fields/#datefield\n.. _DateTimeField: https://docs.djangoproject.com/en/stable/ref/forms/fields/#datetimefield\n.. _DecimalField: https://docs.djangoproject.com/en/stable/ref/forms/fields/#decimalfield\n.. _DurationField: https://docs.djangoproject.com/en/stable/ref/forms/fields/#durationfield\n.. _EmailField: https://docs.djangoproject.com/en/stable/ref/forms/fields/#emailfield\n.. _FloatField: https://docs.djangoproject.com/en/stable/ref/forms/fields/#floatfield\n.. _GenericIPAddressField: https://docs.djangoproject.com/en/stable/ref/forms/fields/#genericipaddressfield\n.. _IntegerField: https://docs.djangoproject.com/en/stable/ref/forms/fields/#integerfield\n.. _ModelChoiceField: https://docs.djangoproject.com/en/stable/ref/forms/fields/#modelchoicefield\n.. _ModelMultipleChoiceField: https://docs.djangoproject.com/en/stable/ref/forms/fields/#modelmultiplechoicefield\n.. _MultipleChoiceField: https://docs.djangoproject.com/en/stable/ref/forms/fields/#multiplechoicefield\n.. _NullBooleanField: https://docs.djangoproject.com/en/stable/ref/forms/fields/#nullbooleanfield\n.. _SlugField: https://docs.djangoproject.com/en/stable/ref/forms/fields/#slugfield\n.. _TimeField: https://docs.djangoproject.com/en/stable/ref/forms/fields/#timefield\n.. _URLField: https://docs.djangoproject.com/en/stable/ref/forms/fields/#urlfield\n.. _UUIDField: https://docs.djangoproject.com/en/stable/ref/forms/fields/#uuidfield\n.. _django-bleach: https://bitbucket.org/tim_heap/django-bleach\n.. _django-ckeditor: https://github.com/django-ckeditor/django-ckeditor\n.. _django-tinymce: https://github.com/aljosa/django-tinymce\n.. _django-markdown: https://github.com/klen/django_markdown\n.. _django-pagedown: https://github.com/timmyomahony/django-pagedown\n.. _django-epiceditor: https://github.com/barraq/django-epiceditor\n.. _django-constance: https://github.com/jezdez/django-constance\n.. _django-dynamic-preferences: https://github.com/EliotBerriot/django-dynamic-preferences\n.. _django-solo: https://github.com/lazybird/django-solo\n.. _django-djconfig: https://github.com/nitely/django-djconfig\n.. _django-aboutconfig: https://bitbucket.org/impala/django-aboutconfig\n.. _django-modelsettings: https://github.com/IlyaSemenov/django-modelsettings\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkezabelle%2Fdjango-stagesetting","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkezabelle%2Fdjango-stagesetting","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkezabelle%2Fdjango-stagesetting/lists"}