Merge pull request #108 from PetrDlouhy/custom_fields

Allow to override field config_type and set custom additional fields
This commit is contained in:
Camilo Nova 2015-12-30 08:15:16 -05:00
commit 803cf465c7
7 changed files with 77 additions and 7 deletions

View file

@ -15,7 +15,9 @@ from django.template.response import TemplateResponse
from django.utils import six
from django.utils.encoding import smart_bytes
from django.utils.formats import localize
from django.utils.module_loading import import_string
from django.utils.translation import ugettext_lazy as _
import django
from . import LazyConfig, settings
@ -42,6 +44,25 @@ FIELDS = {
float: (fields.FloatField, {'widget': NUMERIC_WIDGET}),
}
def parse_additional_fields(fields):
for key in fields:
field = fields[key]
field[0] = import_string(field[0])
if 'widget' in field[1]:
klass = import_string(field[1]['widget'])
field[1]['widget'] = klass(**(field[1].get('widget_kwargs', {}) or {}))
if 'widget_kwargs' in field[1]:
del field[1]['widget_kwargs']
return fields
FIELDS.update(parse_additional_fields(settings.ADDITIONAL_FIELDS))
if not six.PY3:
FIELDS.update({
long: INTEGER_LIKE,
@ -56,8 +77,13 @@ class ConstanceForm(forms.Form):
super(ConstanceForm, self).__init__(*args, initial=initial, **kwargs)
version_hash = hashlib.md5()
for name, (default, help_text) in settings.CONFIG.items():
config_type = type(default)
for name, options in settings.CONFIG.items():
default, help_text = options[0], options[1]
if len(options) == 3:
config_type = options[2]
else:
config_type = type(default)
if config_type not in FIELDS:
raise ImproperlyConfigured(_("Constance doesn't support "
"config values of the type "
@ -103,8 +129,8 @@ class ConstanceAdmin(admin.ModelAdmin):
# First load a mapping between config name and default value
if not self.has_change_permission(request, None):
raise PermissionDenied
default_initial = ((name, default)
for name, (default, help_text) in settings.CONFIG.items())
default_initial = ((name, options[0])
for name, options in settings.CONFIG.items())
# Then update the mapping with actually values from the backend
initial = dict(default_initial,
**dict(config._backend.mget(settings.CONFIG.keys())))
@ -128,7 +154,8 @@ class ConstanceAdmin(admin.ModelAdmin):
'form': form,
'media': self.media + form.media,
}
for name, (default, help_text) in settings.CONFIG.items():
for name, options in settings.CONFIG.items():
default, help_text = options[0], options[1]
# First try to load the value from the actual backend
value = initial.get(name)
# Then if the returned value is None, get the default

View file

@ -11,7 +11,9 @@ class Config(object):
def __getattr__(self, key):
try:
default, help_text = settings.CONFIG[key]
if not len(settings.CONFIG[key]) in (2, 3):
raise AttributeError(key)
default = settings.CONFIG[key][0]
except KeyError:
raise AttributeError(key)
result = self._backend.get(key)

View file

@ -5,6 +5,8 @@ BACKEND = getattr(settings, 'CONSTANCE_BACKEND',
CONFIG = getattr(settings, 'CONSTANCE_CONFIG', {})
ADDITIONAL_FIELDS = getattr(settings, 'CONSTANCE_ADDITIONAL_FIELDS', {})
DATABASE_CACHE_BACKEND = getattr(settings, 'CONSTANCE_DATABASE_CACHE_BACKEND',
None)

View file

@ -36,7 +36,7 @@
{% block bodyclass %}change-list{% endblock %}
{% block content %}
<div id="content-main">
<div id="content-main" class="constance">
<div class="module" id="changelist">
<form id="changelist-form" action="" method="post">{% csrf_token %}
{% if form.errors %}

View file

@ -53,6 +53,33 @@ admin will show.
See the :ref:`Backends <backends>` section how to setup the backend and
finish the configuration.
Custom fields
-------------
You can set the field type by the third value in the `CONSTANCE_CONFIG`
tuple. The value can be string or one of the supported types:
.. code-block:: python
'THE_ANSWER': (42, 'Answer to the Ultimate Question of Life, '
'The Universe, and Everything', str),
If you can add your custom field types, you can use the
`CONSTANCE_ADDITIONAL_FIELDS` variable. Note that you must
use later evaluated strings instead of direct classes:
.. code-block:: python
CONSTANCE_ADDITIONAL_FIELDS = {
'yes_no_null_select': ['django.forms.fields.ChoiceField',
{
'widget': 'django.forms.Select',
'choices': (("-----", None), ("yes", "Yes"), ("no", "No"))
}],
}
CONSTANCE_CONFIG = {
'MY_SELECT_KEY': ('yes', 'select yes or no', 'yes_no_null_select'),
}
Usage
-----

View file

@ -51,6 +51,14 @@ long_value = 123456
if not six.PY3:
long_value = long(long_value)
CONSTANCE_ADDITIONAL_FIELDS = {
'yes_no_null_select': ['django.forms.fields.ChoiceField',
{
'widget': 'django.forms.Select',
'choices': (("-----", None), ("yes", "Yes"), ("no", "No"))
}],
}
CONSTANCE_CONFIG = {
'INT_VALUE': (1, 'some int'),
'LONG_VALUE': (long_value, 'some looong int'),
@ -63,6 +71,7 @@ CONSTANCE_CONFIG = {
'FLOAT_VALUE': (3.1415926536, 'PI'),
'DATE_VALUE': (date(2010, 12, 24), 'Merry Chrismas'),
'TIME_VALUE': (time(23, 59, 59), 'And happy New Year'),
'CHOICE_VALUE': ('yes', 'select yes or no', 'yes_no_null_select'),
'LINEBREAK_VALUE': ('Spam spam', 'eggs\neggs'),
}

View file

@ -27,6 +27,7 @@ class StorageTestsMixin(object):
self.assertEqual(self.config.FLOAT_VALUE, 3.1415926536)
self.assertEqual(self.config.DATE_VALUE, date(2010, 12, 24))
self.assertEqual(self.config.TIME_VALUE, time(23, 59, 59))
self.assertEqual(self.config.CHOICE_VALUE, 'yes')
# set values
self.config.INT_VALUE = 100
@ -39,6 +40,7 @@ class StorageTestsMixin(object):
self.config.FLOAT_VALUE = 2.718281845905
self.config.DATE_VALUE = date(2001, 12, 20)
self.config.TIME_VALUE = time(1, 59, 0)
self.config.CHOICE_VALUE = 'no'
# read again
self.assertEqual(self.config.INT_VALUE, 100)
@ -51,6 +53,7 @@ class StorageTestsMixin(object):
self.assertEqual(self.config.FLOAT_VALUE, 2.718281845905)
self.assertEqual(self.config.DATE_VALUE, date(2001, 12, 20))
self.assertEqual(self.config.TIME_VALUE, time(1, 59, 0))
self.assertEqual(self.config.CHOICE_VALUE, 'no')
def test_nonexistent(self):
try: