Package: django-dbsettings
Storing settings in the databaseNot all settings belong insettings.py, as it has some particular
limitations:Settings are project-wide. This not only requires apps to clutter upsettings.py, but also increases the chances of naming conflicts.Settings are constant throughout an instance of Django. They cannot be
changed without restarting the application.Settings require a programmer in order to be changed. This is true even
if the setting has no functional impact on anything else.Many applications find need to overcome these limitations, anddbsettingsprovides a convenient way to do so.The main goal in using this application is to define a set of placeholders that
will be used to represent the settings that are stored in the database. Then,
the settings may be edited at run-time using the provided editor, and all Python
code in your application that uses the setting will receive the updated value.RequirementsDbsettingsPythonDjango==1.33.8 - 3.102.1 - 4.03.6 - 3.72.1 - 3.23.52.1 - 2.2==1.23.52.1 - 2.23.6 - 3.82.1 - 3.21.0 - 1.1.03.52.0 - 2.23.6 - 3.82.0 - 3.0==0.113.5 - 3.71.10 - 2.22.71.10 - 1.11==0.103.4 - 3.51.7 - 1.103.2 - 3.31.7 - 1.82.71.7 - 1.10==0.93.4 - 3.51.7 - 1.93.2 - 3.31.7 - 1.82.71.7 - 1.9==0.83.21.5 - 1.82.71.4 - 1.82.61.4 - 1.6==0.73.21.5 - 1.72.71.3 - 1.72.61.3 - 1.6==0.63.21.52.6 - 2.71.3 - 1.5<=0.52.6 - 2.71.2* - 1.4* Possibly version below 1.2 will work too, but not tested.InstallationTo install thedbsettingspackage, simply place it anywhere on yourPYTHONPATH.Project settingsIn order to setup database storage, and to let Django know about your use ofdbsettings, simply add it to yourINSTALLED_APPSsetting, like so:INSTALLED_APPS = (
    ...
    'dbsettings',
    ...
)If your Django project utilizessitesframework, all setting would be related
to some site. Ifsitesare not present, settings won’t be connected to any site
(andsitesframework is no longer required since 0.8.1).You can force to do (not) usesitesviaDBSETTINGS_USE_SITES = True / Falseconfiguration variable (put it in project’ssettings.py).By default, values stored in database are limited to 255 characters per setting.
You can change this limit withDBSETTINGS_VALUE_LENGTHconfiguration variable.
If you change this value after migrations were run, you need to manually alter
thedbsettings_settingtable schema.URL ConfigurationIn order to edit your settings at run-time, you’ll need to configure a URL to
access the provided editors. You’ll just need to add a single line, defining
the base URL for the editors, asdbsettingshas its own URLconf to handle
the rest. You may choose any location you like:urlpatterns = patterns('',
    ...
    (r'^settings/', include('dbsettings.urls')),
    ...
)or (django 2):from django.urls import path, include

urlpatterns = [
    ...
    path('settings/', include('dbsettings.urls')),
    ...
]A note about cachingThis framework utilizes Django’s built-incache framework, which is used to
minimize how often the database needs to be accessed. During development,
Django’s built-in server runs in a single process, so all cache backends will
work just fine.Most productions environments, including mod_python, FastCGI or WSGI, run multiple
processes, which some backends don’t fully support. When using thesimpleorlocmembackends, updates to your settings won’t be reflected immediately
in all workers, causing your application to ignore the new changes.No other backends exhibit this behavior, but sincesimpleis the default,
make sure to specify a proper backend when moving to a production environment.Alternatively you can disable caching of settings by settingDBSETTINGS_USE_CACHE = Falseinsettings.py. Beware though: every
access of any setting will result in database hit.By default, entries are cached for a time that is default for the cache. You can
override this by providingDBSETTINGS_CACHE_EXPIRATION. Values interpreted
as seconds, 0 means no caching andNonemeans indefinite caching. Seemore.UsageThese database-backed settings can be applied to any model in any app, or even
in the app itself. All the tools necessary to do so are available within thedbsettingsmodule. A single import provides everything you’ll need:import dbsettingsDefining a group of settingsSettings are be defined in groups that allow them to be referenced together
under a single attribute. Defining a group uses a declarative syntax similar
to that of models, by declaring a new subclass of theGroupclass and
populating it with values.class ImageLimits(dbsettings.Group):
    maximum_width = dbsettings.PositiveIntegerValue()
    maximum_height = dbsettings.PositiveIntegerValue()You may name your groups anything you like, and they may be defined in any
module. This allows them to be imported from common applications if applicable.Defining individual settingsWithin your groups, you may define any number of individual settings by simply
assigning the value types to appropriate names. The names you assign them to
will be the attribute names you’ll use to reference the setting later, so be
sure to choose names accordingly.For the editor, the default description of each setting will be retrieved from
the attribute name, similar to how theverbose_nameof model fields is
retrieved. Also like model fields, however, an optional argument may be provided
to define a more fitting description. It’s recommended to leave the first letter
lower-case, as it will be capitalized as necessary, automatically.class EmailOptions(dbsettings.Group):
    enabled = dbsettings.BooleanValue('whether to send emails or not')
    sender = dbsettings.StringValue('address to send emails from')
    subject = dbsettings.StringValue(default='SiteMail')For more descriptive explanation, thehelp_textargument can be used. It
will be shown in the editor.Thedefaultargument is very useful - it specify an initial value of the
setting.In addition, settings may be supplied with a list of available options, through
the use of of thechoicesargument. This works exactly like thechoicesargument for model fields, and that of the newformsChoiceField.
When usingchoices, aget_FOO_displaymethod is added to settings, for example:country = dbsettings.StringValue(choices=(("USA", "United States"), ("BR", "Brazil")))

>>> settings.country
"USA"
>>> settings.get_country_display()
"United States"The widget used for a value can be overriden using thewidgetkeyword. For example:payment_instructions = dbsettings.StringValue(
    help_text="Printed on every invoice.",
    default="Payment to Example XYZ\nBank name here\nAccount: 0123456\nSort: 01-02-03",
    widget=forms.Textarea
)A full list of value types is available later in this document, but the process
and arguments are the same for each.Assigning settingsOnce your settings are defined and grouped properly, they must be assigned to a
location where they will be referenced later. This is as simple as instantiating
the settings group in the appropriate location. This may be at the module level
or within any standard Django model.Group instance may receive one optional argument: verbose name of the group.
This name will be displayed in the editor.email = EmailOptions()

class Image(models.Model):
    image = models.ImageField(upload_to='/upload/path')
    caption = models.TextField()

    limits = ImageLimits('Dimension settings')Multiple groups may be assigned to the same module or model, and they can even
be combined into a single group by using standard addition syntax:options = EmailOptions() + ImageLimits()To separate and tag settings nicely in the editor, use verbose names:options = EmailOptions('Email') + ImageLimits('Dimesions')Database setupA single model is provided for database storage, and this model must be
installed in your database before you can use the included editors or the
permissions that will be automatically created. This is a simple matter of
runningmanage.py syncdbormanage.py migratenow that your settings
are configured.This step need only be repeate when settings are added to a new application,
as it will create the appropriate permissions. Once those are in place, new
settings may be added to existing applications with no impact on the database.Using your settingsOnce the above steps are completed, you’re ready to make use of database-backed
settings.Editing settingsWhen first defined, your settings will default toNone(orFalsein
the case ofBooleanValue), so their values must be set using one of the
supplied editors before they can be considered useful (however, if the setting
had thedefaultargument passed in the constructor, its value is already
useful - equal to the defined default).The editor will be available at the URL configured earlier.
For example, if you used the prefix of'settings/', the URL/settings/will provide an editor of all available settings, while/settings/myapp/would contain a list of just the settings formyapp.URL patterns are named:'site_settings'and'app_settings', respectively.The editors are restricted to staff members, and the particular settings that
will be available to users is based on permissions that are set for them. This
means that superusers will automatically be able to edit all settings, while
other staff members will need to have permissions set explicitly.Accessing settings in PythonOnce settings have been assigned to an appropriate location, they may be
referenced as standard Python attributes. The group becomes an attribute of the
location where it was assigned, and the individual values are attributes of the
group.If any settings are referenced without being set to a particular value, they
will default toNone(orFalsein the case ofBooleanValue, or
whatever was passed asdefault). In the
following example, assume thatEmailOptionswere just added to the project
and theImageLimitswere added earlier and already set via editor.>>> from myproject.myapp import models

# EmailOptions are not defined
>>> models.email.enabled
False
>>> models.email.sender
>>> models.email.subject
'SiteMail'  # Since default was defined

# ImageLimits are defined
>>> models.Image.limits.maximum_width
1024
>>> models.Image.limits.maximum_height
768These settings are accessible from any Python code, making them especially
useful in model methods and views. Each time the attribute is accessed, it will
retrieve the current value, so your code doesn’t need to worry about what
happens behind the scenes.def is_valid(self):
    if self.width > Image.limits.maximum_width:
        return False
    if self.height > Image.limits.maximum_height:
        return False
return TrueAs mentioned, views can make use of these settings as well.from myproject.myapp.models import email

def submit(request):

    ...
    # Deal with a form submission
    ...

    if email.enabled:
        from django.core.mail import send_mail
    send_mail(email.subject, 'message', email.sender, [request.user.email])Settings can be not only read, but also written. The admin editor is more
user-friendly, but in case code need to change something:from myproject.myapp.models import Image

def low_disk_space():
    Image.limits.maximum_width = Image.limits.maximum_height = 200Every write is immediately commited to the database and proper cache key is deleted.A note about model instancesSince settings aren’t related to individual model instances, any settings that
are set on models may only be accessed by the model class itself. Attempting to
access settings on an instance will raise anAttributeError.Triggering actions on settings changesA signal is sent whenever a setting changes. You can receive it by doing
something like this in your appconfig’sready()method:from dbsetting.loading import get_setting
from dbsettings.signals import setting_changed

setting_changed.connect(my_function, sender=get_setting('myapp', 'MyClass', 'myattr'))my_functionwill be called with asenderandvalueparameters, the latter containing a
new value assigned to the setting.Value typesThere are several various value types available for database-backed settings.
Select the one most appropriate for each individual setting, but all types use
the same set of arguments.BooleanValuePresents a checkbox in the editor, and returnsTrueorFalsein Python.DurationValuePresents a set of inputs suitable for specifying a length of time. This is
represented in Python as atimedeltaobject.FloatValuePresents a standard input field, which becomes afloatin Python.IntegerValuePresents a standard input field, which becomes anintin Python.PercentValueSimilar toIntegerValue, but with a limit requiring that the value be
between 0 and 100. In addition, when accessed in Python, the value will be
divided by 100, so that it is immediately suitable for calculations.For instance, if amyapp.taxes.sales_taxwas set to 5 in the editor,
the following calculation would be valid:>>> 5.00 * myapp.taxes.sales_tax
0.25PositiveIntegerValueSimilar toIntegerValue, but limited to positive values and 0.StringValuePresents a standard input, accepting any text string up to 255
(orDBSETTINGS_VALUE_LENGTH) characters. In
Python, the value is accessed as a standard string.DateTimeValuePresents a standard input field, which becomes adatetimein Python.User input will be parsed according toDATETIME_INPUT_FORMATSsetting.In code, one can assign to field string or datetime object:# These two statements has the same effect
myapp.Feed.next_feed = '2012-06-01 00:00:00'
myapp.Feed.next_feed = datetime.datetime(2012, 6, 1, 0, 0, 0)DateValuePresents a standard input field, which becomes adatein Python.User input will be parsed according toDATE_INPUT_FORMATSsetting.SeeDateTimeValuefor the remark about assigning.TimeValuePresents a standard input field, which becomes atimein Python.User input will be parsed according toTIME_INPUT_FORMATSsetting.SeeDateTimeValuefor the remark about assigning.ImageValue(requires PIL or Pillow imaging library to work)Allows to upload image and view its preview.ImageValue has optional keyword arguments:upload_tospecifies path (relative toMEDIA_ROOT), where uploaded
images will be stored. If argument is not present, files will be saved
directly underMEDIA_ROOT.delete_old(default to True) controls whether to delete the old file when
the value has changedIn Python, the value is accessed as a standard string (file name, relative toMEDIA_ROOT).PasswordValuePresents a standard password input. Retain old setting value if not changed.Setting defaults for a distributed applicationDistributed applications often have need for certain default settings that are
useful for the common case, but which may be changed to suit individual
installations. For such cases, a utility is provided to enable applications to
set any applicable defaults.Living atdbsettings.utils.set_defaults, this utility is designed to be used
within the app’smanagement.py. This way, when the application is installed
usingsyncdb/migrate, the default settings will also be installed to the database.The function requires a single positional argument, which is themodelsmodule for the application. Any additional arguments must represent the actual
settings that will be installed. Each argument is a 3-tuple, of the following
format:(class_name, setting_name, value).If the value is intended for a module-level setting, simply setclass_nameto an empty string. The value forsetting_nameshould be the name given to
the setting itself, while the name assigned to the group isn’t supplied, as it
isn’t used for storing the value.For example, the following code inmanagement.pywould set defaults for
some of the settings provided earlier in this document:from django.conf import settings
from dbsettings.utils import set_defaults
from myproject.myapp import models as myapp

set_defaults(myapp,
    ('', 'enabled', True)
    ('', 'sender', settings.ADMINS[0][1]) # Email of the first listed admin
    ('Image', 'maximum_width', 800)
    ('Image', 'maximum_height', 600)
)Changelog1.3.0(19/02/2022)Added compatibility with Django 4.0 (thanks nerdoc)Fixed misleading message (about permissions) in the editor if no settings were definedFixed bug with app-level settings not present in the editor ifverbose_namewas not set1.2.0(16/12/2021)Fixed exception handling in cache operation and addedDBSETTINGS_CACHE_EXPIRATION(thanks AminHP)Addedget_FOO_displaymethod for fields which havechoices(thanks paulogiacomelli)Use Django storage framework for ImageValue instead of manual filesystem handling (thanks j0nm1)Dropped compatibility with Django 2.01.1.0(21/03/2020)Fixed image widget in Django 2.1Addeddelete_oldparameter to ImageValueMakeupload_toparameter to ImageValue no longer required.Fix PasswordValue to not render widget as required.1.0.1(26/12/2019)Introduced a signalsetting_changedAdded compatibility with Django 3.0Dropped compatibility with Django 1.10, 1.11Dropped compatibility with Python 20.11.0(31/07/2019)Added compatibility with Django 1.11, 2.0, 2.1, 2.2Dropped compatibility with Django 1.7, 1.8, 1.90.10.0(25/09/2016)Added compatibility with Django 1.100.9.3(02/06/2016)Fixed (hopefully for good) problem with ImageValue in Python 3 (thanks rolexCoder)0.9.2(01/05/2016)Fixed bug when saving non-required settingsFixed problem with ImageValue in Python 3 (thanks rolexCoder)0.9.1(10/01/2016)FixedSitesapp being optional (thanks rolexCoder)0.9.0(25/12/2015)Added compatibility with Django 1.9 (thanks Alonso)Dropped compatibility with Django 1.4, 1.5, 1.60.8.2(17/09/2015)Added migrations to distroAdd configuration option to change max length of setting values from 255 to whateverAdd configuration option to disable caching (thanks nwaxiomatic)Fixed PercentValue rendering (thanks last-partizan)0.8.1(21/06/2015)Madedjango.contrib.sitesframework dependency optionalAdded migration for app0.8.0(16/04/2015)Switched to using django.utils.six instead of standalone six.Added compatibility with Django 1.8Dropped compatibility with Django 1.30.7.4(24/03/2015)Added default values for fields.Fixed Python 3.3 compatibilityAdded creation of folders with ImageValue0.7.3,0.7.2pypi problems0.7.1(11/03/2015)Fixed pypi distribution.0.7(06/07/2014)Added PasswordValueAdded compatibility with Django 1.6 and 1.7.0.6(16/09/2013)Added compatibility with Django 1.5 and python3, dropped support for Django 1.2.Fixed permissions: added permission for editing non-model (module-level) settingsMake PIL/Pillow not required in setup.py0.5(11/10/2012)Fixed error occuring when test are run withLANGUAGE_CODEdifferent than ‘en’Added verbose_name option for GroupsCleaned code0.4.1(02/10/2012)Fixed Image import0.4(30/09/2012)Named urlsAdded polish translation0.3(04/09/2012)Included testrunner in distribution0.2(05/07/2012)Fixed errors appearing when module-level and model-level settings have
same attribute namesCorrected the editor templates admin integrationUpdated README0.1(29/06/2012)Initial PyPI release