clean up the config app. Use jsonfield to save the config values.
Syncdb necessary.
This commit is contained in:
parent
15621b7702
commit
e01d456e7b
@ -10,19 +10,59 @@
|
|||||||
:license: GNU GPL, see LICENSE for more details.
|
:license: GNU GPL, see LICENSE for more details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.forms import Form, CharField, TextInput, BooleanField, IntegerField, ChoiceField, Textarea, Select
|
from django import forms
|
||||||
|
|
||||||
from utils.forms import CssClassMixin
|
from utils.forms import CssClassMixin
|
||||||
from models import config
|
from models import config
|
||||||
from utils.translation_ext import ugettext as _
|
from utils.translation_ext import ugettext as _
|
||||||
|
|
||||||
|
|
||||||
class GeneralConfigForm(Form, CssClassMixin):
|
class GeneralConfigForm(forms.Form, CssClassMixin):
|
||||||
event_name = CharField(widget=TextInput(),label=_("Event name"), max_length=30)
|
event_name = forms.CharField(
|
||||||
event_description = CharField(widget=TextInput(),label=_("Short description of event"), max_length=100, required=False)
|
widget=forms.TextInput(),
|
||||||
event_date = CharField(widget=TextInput(), required=False, label=_("Event date"))
|
label=_("Event name"),
|
||||||
event_location = CharField(widget=TextInput(), required=False, label=_("Event location"))
|
max_length=30,
|
||||||
event_organizer = CharField(widget=TextInput(), required=False, label=_("Event organizer"))
|
)
|
||||||
system_enable_anonymous = BooleanField(required=False, label=_("Allow access for anonymous guest users") )
|
|
||||||
frontpage_title = CharField(widget=TextInput(), required=False, label=_("Title") )
|
event_description = forms.CharField(
|
||||||
frontpage_welcometext = CharField(widget=Textarea(), required=False, label=_("Welcome text") )
|
widget=forms.TextInput(),
|
||||||
|
label=_("Short description of event"),
|
||||||
|
required=False,
|
||||||
|
max_length=100,
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
event_date = forms.CharField(
|
||||||
|
widget=forms.TextInput(),
|
||||||
|
label=_("Event date"),
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
event_location = forms.CharField(
|
||||||
|
widget=forms.TextInput(),
|
||||||
|
label=_("Event location"),
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
event_organizer = forms.CharField(
|
||||||
|
widget=forms.TextInput(),
|
||||||
|
label=_("Event organizer"),
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
system_enable_anonymous = forms.BooleanField(
|
||||||
|
label=_("Allow access for anonymous guest users"),
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
frontpage_title = forms.CharField(
|
||||||
|
widget=forms.TextInput(),
|
||||||
|
label=_("Title"),
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
frontpage_welcometext = forms.CharField(
|
||||||
|
widget=forms.Textarea(),
|
||||||
|
label=_("Welcome text"),
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
|
@ -9,21 +9,26 @@
|
|||||||
:copyright: 2011, 2012 by OpenSlides team, see AUTHORS.
|
:copyright: 2011, 2012 by OpenSlides team, see AUTHORS.
|
||||||
:license: GNU GPL, see LICENSE for more details.
|
:license: GNU GPL, see LICENSE for more details.
|
||||||
"""
|
"""
|
||||||
from pickle import dumps, loads
|
|
||||||
import base64
|
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
from django.utils.importlib import import_module
|
||||||
|
from django.utils.translation import ugettext as _, ugettext_noop
|
||||||
|
|
||||||
from utils.translation_ext import ugettext as _
|
from openslides.utils.jsonfield import JSONField
|
||||||
|
from openslides.utils.signals import template_manipulation
|
||||||
|
|
||||||
from openslides.config.signals import default_config_value
|
from openslides.config.signals import default_config_value
|
||||||
import settings
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigStore(models.Model):
|
class ConfigStore(models.Model):
|
||||||
|
"""
|
||||||
|
Stores the config values.
|
||||||
|
"""
|
||||||
key = models.CharField(max_length=100, primary_key=True)
|
key = models.CharField(max_length=100, primary_key=True)
|
||||||
value = models.TextField()
|
value = JSONField()
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.key
|
return self.key
|
||||||
@ -31,41 +36,23 @@ class ConfigStore(models.Model):
|
|||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = 'config'
|
verbose_name = 'config'
|
||||||
permissions = (
|
permissions = (
|
||||||
('can_manage_config', _("Can manage configuration", fixstr=True)),
|
('can_manage_config', ugettext_noop("Can manage configuration")),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# TODO:
|
|
||||||
# I used base64 to save pickled Data, there has to be another way see:
|
|
||||||
# http://stackoverflow.com/questions/2524970/djangounicodedecodeerror-while-storing-pickled-data
|
|
||||||
|
|
||||||
class Config(object):
|
class Config(object):
|
||||||
def load_config(self):
|
"""
|
||||||
self.config = {}
|
Access the config values via config[...]
|
||||||
for key, value in ConfigStore.objects.all().values_list():
|
"""
|
||||||
self.config[key] = loads(base64.decodestring(str(value)))
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
# Had to be deactivated, because in more than one thread the values have
|
|
||||||
# to be loaded on each request.
|
|
||||||
## try:
|
|
||||||
## self.config
|
|
||||||
## except AttributeError:
|
|
||||||
## self.load_config()
|
|
||||||
## try:
|
|
||||||
## return self.config[key]
|
|
||||||
## except KeyError:
|
|
||||||
## pass
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return loads(base64.decodestring(str(ConfigStore.objects.get(key=key).value)))
|
return ConfigStore.objects.get(key=key).value
|
||||||
except ConfigStore.DoesNotExist:
|
except ConfigStore.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
for receiver, value in default_config_value.send(sender='config', key=key):
|
for receiver, value in default_config_value.send(sender='config',
|
||||||
|
key=key):
|
||||||
if value is not None:
|
if value is not None:
|
||||||
# if settings.DEBUG:
|
|
||||||
# print 'Using default for %s' % key
|
|
||||||
return value
|
return value
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
print "No default value for: %s" % key
|
print "No default value for: %s" % key
|
||||||
@ -76,22 +63,25 @@ class Config(object):
|
|||||||
c = ConfigStore.objects.get(pk=key)
|
c = ConfigStore.objects.get(pk=key)
|
||||||
except ConfigStore.DoesNotExist:
|
except ConfigStore.DoesNotExist:
|
||||||
c = ConfigStore(pk=key)
|
c = ConfigStore(pk=key)
|
||||||
c.value = base64.encodestring(dumps(value))
|
c.value = value
|
||||||
c.save()
|
c.save()
|
||||||
try:
|
|
||||||
self.config[key] = value
|
def __contains__(self, item):
|
||||||
except AttributeError:
|
return ConfigStore.objects.filter(key=item).exists()
|
||||||
self.load_config()
|
|
||||||
self.config[key] = value
|
|
||||||
|
|
||||||
config = Config()
|
config = Config()
|
||||||
|
|
||||||
|
|
||||||
@receiver(default_config_value, dispatch_uid="config_default_config")
|
@receiver(default_config_value, dispatch_uid="config_default_config")
|
||||||
def default_config(sender, key, **kwargs):
|
def default_config(sender, key, **kwargs):
|
||||||
|
"""
|
||||||
|
Global default values.
|
||||||
|
"""
|
||||||
return {
|
return {
|
||||||
'event_name': 'OpenSlides',
|
'event_name': 'OpenSlides',
|
||||||
'event_description': _('Presentation system for agenda, applications and elections'),
|
'event_description':
|
||||||
|
_('Presentation system for agenda, applications and elections'),
|
||||||
'event_date': '',
|
'event_date': '',
|
||||||
'event_location': '',
|
'event_location': '',
|
||||||
'event_organizer': '',
|
'event_organizer': '',
|
||||||
@ -99,25 +89,23 @@ def default_config(sender, key, **kwargs):
|
|||||||
'frontpage_title': _('Welcome'),
|
'frontpage_title': _('Welcome'),
|
||||||
'frontpage_welcometext': _('Welcome to OpenSlides!'),
|
'frontpage_welcometext': _('Welcome to OpenSlides!'),
|
||||||
'show_help_text': True,
|
'show_help_text': True,
|
||||||
'help_text': _("Get professional support for OpenSlides on %s.") % "<a href='http://openslides.org/' target='_blank'>www.openslides.org</a>",
|
'help_text': _("Get professional support for OpenSlides on %s.") %
|
||||||
|
"<a href='http://openslides.org/' target='_blank'> \
|
||||||
|
www.openslides.org</a>",
|
||||||
'system_enable_anonymous': False,
|
'system_enable_anonymous': False,
|
||||||
}.get(key)
|
}.get(key)
|
||||||
|
|
||||||
|
|
||||||
from django.dispatch import receiver
|
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.utils.importlib import import_module
|
|
||||||
import settings
|
|
||||||
|
|
||||||
from openslides.utils.signals import template_manipulation
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(template_manipulation, dispatch_uid="config_submenu")
|
@receiver(template_manipulation, dispatch_uid="config_submenu")
|
||||||
def set_submenu(sender, request, context, **kwargs):
|
def set_submenu(sender, request, context, **kwargs):
|
||||||
|
"""
|
||||||
|
Submenu for the config tab.
|
||||||
|
"""
|
||||||
if not request.path.startswith('/config/'):
|
if not request.path.startswith('/config/'):
|
||||||
return None
|
return None
|
||||||
menu_links = [
|
menu_links = [
|
||||||
(reverse('config_general'), _('General'), request.path == reverse('config_general') ),
|
(reverse('config_general'), _('General'),
|
||||||
|
request.path == reverse('config_general')),
|
||||||
]
|
]
|
||||||
|
|
||||||
for app in settings.INSTALLED_APPS:
|
for app in settings.INSTALLED_APPS:
|
||||||
@ -139,7 +127,8 @@ def set_submenu(sender, request, context, **kwargs):
|
|||||||
)
|
)
|
||||||
|
|
||||||
menu_links.append (
|
menu_links.append (
|
||||||
(reverse('config_version'), _('Version'), request.path == reverse('config_version') )
|
(reverse('config_version'), _('Version'),
|
||||||
|
request.path == reverse('config_version'))
|
||||||
)
|
)
|
||||||
|
|
||||||
context.update({
|
context.update({
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
openslides.config.signals
|
openslides.config.signals
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Defines Signals for the config.
|
Defines Signals for the config.
|
||||||
|
|
||||||
|
@ -10,14 +10,13 @@
|
|||||||
:license: GNU GPL, see LICENSE for more details.
|
:license: GNU GPL, see LICENSE for more details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.conf.urls.defaults import *
|
from django.conf import settings
|
||||||
|
from django.conf.urls.defaults import patterns, url
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
|
|
||||||
import settings
|
from openslides.config.views import GeneralConfig, VersionConfig
|
||||||
|
|
||||||
from views import GeneralConfig, VersionConfig
|
urlpatterns = patterns('',
|
||||||
|
|
||||||
urlpatterns = patterns('config.views',
|
|
||||||
url(r'^general/$',
|
url(r'^general/$',
|
||||||
GeneralConfig.as_view(),
|
GeneralConfig.as_view(),
|
||||||
name='config_general',
|
name='config_general',
|
||||||
|
@ -10,27 +10,26 @@
|
|||||||
:license: GNU GPL, see LICENSE for more details.
|
:license: GNU GPL, see LICENSE for more details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.shortcuts import redirect
|
from django.conf import settings
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.models import Group, Permission
|
from django.contrib.auth.models import Group, Permission
|
||||||
from django.utils.translation import ugettext as _
|
from django.core.urlresolvers import reverse
|
||||||
from django.template.loader import render_to_string
|
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
import settings
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from openslides import get_version
|
from openslides import get_version
|
||||||
|
|
||||||
from utils.utils import template, permission_required
|
from openslides.utils.template import Tab
|
||||||
from utils.views import FormView, TemplateView
|
from openslides.utils.views import FormView, TemplateView
|
||||||
from utils.template import Tab
|
|
||||||
|
|
||||||
from forms import GeneralConfigForm
|
from openslides.config.forms import GeneralConfigForm
|
||||||
|
from openslides.config.models import config
|
||||||
from models import config
|
|
||||||
|
|
||||||
|
|
||||||
class GeneralConfig(FormView):
|
class GeneralConfig(FormView):
|
||||||
|
"""
|
||||||
|
Gereral config values.
|
||||||
|
"""
|
||||||
permission_required = 'config.can_manage_config'
|
permission_required = 'config.can_manage_config'
|
||||||
form_class = GeneralConfigForm
|
form_class = GeneralConfigForm
|
||||||
template_name = 'config/general.html'
|
template_name = 'config/general.html'
|
||||||
@ -57,7 +56,8 @@ class GeneralConfig(FormView):
|
|||||||
|
|
||||||
# frontpage
|
# frontpage
|
||||||
config['frontpage_title'] = form.cleaned_data['frontpage_title']
|
config['frontpage_title'] = form.cleaned_data['frontpage_title']
|
||||||
config['frontpage_welcometext'] = form.cleaned_data['frontpage_welcometext']
|
config['frontpage_welcometext'] = \
|
||||||
|
form.cleaned_data['frontpage_welcometext']
|
||||||
|
|
||||||
# system
|
# system
|
||||||
if form.cleaned_data['system_enable_anonymous']:
|
if form.cleaned_data['system_enable_anonymous']:
|
||||||
@ -66,21 +66,29 @@ class GeneralConfig(FormView):
|
|||||||
try:
|
try:
|
||||||
anonymous = Group.objects.get(name='Anonymous')
|
anonymous = Group.objects.get(name='Anonymous')
|
||||||
except Group.DoesNotExist:
|
except Group.DoesNotExist:
|
||||||
default_perms = [u'can_see_agenda', u'can_see_projector', u'can_see_application']
|
default_perms = [u'can_see_agenda', u'can_see_projector',
|
||||||
|
u'can_see_application']
|
||||||
anonymous = Group()
|
anonymous = Group()
|
||||||
anonymous.name = 'Anonymous'
|
anonymous.name = 'Anonymous'
|
||||||
anonymous.save()
|
anonymous.save()
|
||||||
anonymous.permissions = Permission.objects.filter(codename__in=default_perms)
|
anonymous.permissions = Permission.objects.filter(
|
||||||
|
codename__in=default_perms)
|
||||||
anonymous.save()
|
anonymous.save()
|
||||||
messages.success(self.request, _('Anonymous access enabled. Please modify the "Anonymous" group to fit your required permissions.'))
|
messages.success(self.request,
|
||||||
|
_('Anonymous access enabled. Please modify the "Anonymous" \
|
||||||
|
group to fit your required permissions.'))
|
||||||
else:
|
else:
|
||||||
config['system_enable_anonymous'] = False
|
config['system_enable_anonymous'] = False
|
||||||
|
|
||||||
messages.success(self.request, _('General settings successfully saved.'))
|
messages.success(self.request,
|
||||||
|
_('General settings successfully saved.'))
|
||||||
return super(GeneralConfig, self).form_valid(form)
|
return super(GeneralConfig, self).form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
class VersionConfig(TemplateView):
|
class VersionConfig(TemplateView):
|
||||||
|
"""
|
||||||
|
Show version infos.
|
||||||
|
"""
|
||||||
permission_required = 'config.can_manage_config'
|
permission_required = 'config.can_manage_config'
|
||||||
template_name = 'config/version.html'
|
template_name = 'config/version.html'
|
||||||
|
|
||||||
@ -99,12 +107,14 @@ class VersionConfig(TemplateView):
|
|||||||
plugin_name = mod.__name__.split('.')[0]
|
plugin_name = mod.__name__.split('.')[0]
|
||||||
|
|
||||||
context['versions'].append((plugin_name, plugin_version))
|
context['versions'].append((plugin_name, plugin_version))
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
def register_tab(request):
|
def register_tab(request):
|
||||||
selected = True if request.path.startswith('/config/') else False
|
"""
|
||||||
|
Register the config tab.
|
||||||
|
"""
|
||||||
|
selected = request.path.startswith('/config/')
|
||||||
return Tab(
|
return Tab(
|
||||||
title=_('Configuration'),
|
title=_('Configuration'),
|
||||||
url=reverse('config_general'),
|
url=reverse('config_general'),
|
||||||
|
@ -186,13 +186,8 @@ def set_system_url(url):
|
|||||||
from openslides.config.models import config
|
from openslides.config.models import config
|
||||||
|
|
||||||
key = "participant_pdf_system_url"
|
key = "participant_pdf_system_url"
|
||||||
try:
|
if key in config:
|
||||||
if key in config.config:
|
return
|
||||||
return
|
|
||||||
except AttributeError:
|
|
||||||
config.load_config()
|
|
||||||
if key in config.config:
|
|
||||||
return
|
|
||||||
config[key] = url
|
config[key] = url
|
||||||
|
|
||||||
|
|
||||||
|
13
openslides/utils/jsonfield/README
Normal file
13
openslides/utils/jsonfield/README
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
https://github.com/bradjasper/django-jsonfield
|
||||||
|
|
||||||
|
django-jsonfield is a reusable django field that allows you to store validated JSON in your model.
|
||||||
|
|
||||||
|
It silently takes care of serialization. To use, simple add the field to one of your models.
|
||||||
|
|
||||||
|
===
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
from jsonfield import JSONField
|
||||||
|
|
||||||
|
class MyModel(models.Model):
|
||||||
|
json = JSONField()
|
1
openslides/utils/jsonfield/__init__.py
Normal file
1
openslides/utils/jsonfield/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from fields import JSONField
|
75
openslides/utils/jsonfield/fields.py
Normal file
75
openslides/utils/jsonfield/fields.py
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
from django.db import models
|
||||||
|
from django.core.serializers.json import DjangoJSONEncoder
|
||||||
|
from django.utils import simplejson as json
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from django.forms.fields import Field
|
||||||
|
from django.forms.util import ValidationError as FormValidationError
|
||||||
|
|
||||||
|
class JSONFormField(Field):
|
||||||
|
def clean(self, value):
|
||||||
|
|
||||||
|
if not value and not self.required:
|
||||||
|
return None
|
||||||
|
|
||||||
|
value = super(JSONFormField, self).clean(value)
|
||||||
|
|
||||||
|
if isinstance(value, basestring):
|
||||||
|
try:
|
||||||
|
json.loads(value)
|
||||||
|
except ValueError:
|
||||||
|
raise FormValidationError(_("Enter valid JSON"))
|
||||||
|
return value
|
||||||
|
|
||||||
|
class JSONField(models.TextField):
|
||||||
|
"""JSONField is a generic textfield that serializes/unserializes JSON objects"""
|
||||||
|
|
||||||
|
# Used so to_python() is called
|
||||||
|
__metaclass__ = models.SubfieldBase
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.dump_kwargs = kwargs.pop('dump_kwargs', {'cls': DjangoJSONEncoder})
|
||||||
|
self.load_kwargs = kwargs.pop('load_kwargs', {})
|
||||||
|
|
||||||
|
super(JSONField, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def to_python(self, value):
|
||||||
|
"""Convert string value to JSON"""
|
||||||
|
if isinstance(value, basestring):
|
||||||
|
try:
|
||||||
|
return json.loads(value, **self.load_kwargs)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
return value
|
||||||
|
|
||||||
|
def get_db_prep_value(self, value, connection, prepared=False):
|
||||||
|
"""Convert JSON object to a string"""
|
||||||
|
|
||||||
|
if isinstance(value, basestring):
|
||||||
|
return value
|
||||||
|
return json.dumps(value, **self.dump_kwargs)
|
||||||
|
|
||||||
|
def value_to_string(self, obj):
|
||||||
|
value = self._get_val_from_obj(obj)
|
||||||
|
return self.get_prep_value(value)
|
||||||
|
|
||||||
|
def value_from_object(self, obj):
|
||||||
|
return json.dumps(super(JSONField, self).value_from_object(obj))
|
||||||
|
|
||||||
|
def formfield(self, **kwargs):
|
||||||
|
|
||||||
|
if "form_class" not in kwargs:
|
||||||
|
kwargs["form_class"] = JSONFormField
|
||||||
|
|
||||||
|
field = super(JSONField, self).formfield(**kwargs)
|
||||||
|
|
||||||
|
if not field.help_text:
|
||||||
|
field.help_text = "Enter valid JSON"
|
||||||
|
|
||||||
|
return field
|
||||||
|
|
||||||
|
try:
|
||||||
|
from south.modelsinspector import add_introspection_rules
|
||||||
|
add_introspection_rules([], ["^jsonfield\.fields\.JSONField"])
|
||||||
|
except ImportError:
|
||||||
|
pass
|
1
openslides/utils/jsonfield/models.py
Normal file
1
openslides/utils/jsonfield/models.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
# Django needs this to see it as a project
|
108
openslides/utils/jsonfield/tests.py
Normal file
108
openslides/utils/jsonfield/tests.py
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
from django.db import models
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.utils import simplejson as json
|
||||||
|
|
||||||
|
from fields import JSONField
|
||||||
|
|
||||||
|
|
||||||
|
class JsonModel(models.Model):
|
||||||
|
json = JSONField()
|
||||||
|
|
||||||
|
|
||||||
|
class ComplexEncoder(json.JSONEncoder):
|
||||||
|
def default(self, obj):
|
||||||
|
if isinstance(obj, complex):
|
||||||
|
return {
|
||||||
|
'__complex__': True,
|
||||||
|
'real': obj.real,
|
||||||
|
'imag': obj.imag,
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.JSONEncoder.default(self, obj)
|
||||||
|
|
||||||
|
|
||||||
|
def as_complex(dct):
|
||||||
|
if '__complex__' in dct:
|
||||||
|
return complex(dct['real'], dct['imag'])
|
||||||
|
return dct
|
||||||
|
|
||||||
|
|
||||||
|
class JSONModelCustomEncoders(models.Model):
|
||||||
|
# A JSON field that can store complex numbers
|
||||||
|
json = JSONField(
|
||||||
|
dump_kwargs={'cls': ComplexEncoder},
|
||||||
|
load_kwargs={'object_hook': as_complex},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class JSONFieldTest(TestCase):
|
||||||
|
"""JSONField Wrapper Tests"""
|
||||||
|
|
||||||
|
def test_json_field_create(self):
|
||||||
|
"""Test saving a JSON object in our JSONField"""
|
||||||
|
|
||||||
|
json_obj = {
|
||||||
|
"item_1": "this is a json blah",
|
||||||
|
"blergh": "hey, hey, hey"}
|
||||||
|
|
||||||
|
obj = JsonModel.objects.create(json=json_obj)
|
||||||
|
new_obj = JsonModel.objects.get(id=obj.id)
|
||||||
|
|
||||||
|
self.failUnlessEqual(new_obj.json, json_obj)
|
||||||
|
|
||||||
|
def test_json_field_modify(self):
|
||||||
|
"""Test modifying a JSON object in our JSONField"""
|
||||||
|
|
||||||
|
json_obj_1 = {'a': 1, 'b': 2}
|
||||||
|
json_obj_2 = {'a': 3, 'b': 4}
|
||||||
|
|
||||||
|
obj = JsonModel.objects.create(json=json_obj_1)
|
||||||
|
|
||||||
|
self.failUnlessEqual(obj.json, json_obj_1)
|
||||||
|
|
||||||
|
obj.json = json_obj_2
|
||||||
|
|
||||||
|
self.failUnlessEqual(obj.json, json_obj_2)
|
||||||
|
|
||||||
|
obj.save()
|
||||||
|
|
||||||
|
self.failUnlessEqual(obj.json, json_obj_2)
|
||||||
|
|
||||||
|
self.assert_(obj)
|
||||||
|
|
||||||
|
def test_json_field_load(self):
|
||||||
|
"""Test loading a JSON object from the DB"""
|
||||||
|
|
||||||
|
json_obj_1 = {'a': 1, 'b': 2}
|
||||||
|
|
||||||
|
obj = JsonModel.objects.create(json=json_obj_1)
|
||||||
|
|
||||||
|
new_obj = JsonModel.objects.get(id=obj.id)
|
||||||
|
|
||||||
|
self.failUnlessEqual(new_obj.json, json_obj_1)
|
||||||
|
|
||||||
|
def test_json_list(self):
|
||||||
|
"""Test storing a JSON list"""
|
||||||
|
|
||||||
|
json_obj = ["my", "list", "of", 1, "objs", {"hello": "there"}]
|
||||||
|
|
||||||
|
obj = JsonModel.objects.create(json=json_obj)
|
||||||
|
new_obj = JsonModel.objects.get(id=obj.id)
|
||||||
|
self.failUnlessEqual(new_obj.json, json_obj)
|
||||||
|
|
||||||
|
def test_empty_objects(self):
|
||||||
|
"""Test storing empty objects"""
|
||||||
|
|
||||||
|
for json_obj in [{}, [], 0, '', False]:
|
||||||
|
obj = JsonModel.objects.create(json=json_obj)
|
||||||
|
new_obj = JsonModel.objects.get(id=obj.id)
|
||||||
|
self.failUnlessEqual(json_obj, obj.json)
|
||||||
|
self.failUnlessEqual(json_obj, new_obj.json)
|
||||||
|
|
||||||
|
def test_custom_encoder(self):
|
||||||
|
"""Test encoder_cls and object_hook"""
|
||||||
|
value = 1 + 3j # A complex number
|
||||||
|
|
||||||
|
obj = JSONModelCustomEncoders.objects.create(json=value)
|
||||||
|
new_obj = JSONModelCustomEncoders.objects.get(pk=obj.pk)
|
||||||
|
self.failUnlessEqual(value, new_obj.json)
|
Loading…
Reference in New Issue
Block a user