Commit 2b87cd44 authored by Paul Brown's avatar Paul Brown

add JSONField to SQLA backend

parent 32921060
import json
import warnings
import geoalchemy2
from flask import current_app
from shapely.geometry import shape
from sqlalchemy import func
from wtforms.fields import TextAreaField
from .widgets import LeafletWidget
class JSONField(TextAreaField):
def _value(self):
if self.raw_data:
return self.raw_data[0]
if self.data:
return self.data
return ""
def process_formdata(self, valuelist):
if valuelist:
value = valuelist[0]
if not value:
self.data = None
return
try:
self.data = self.from_json(value)
except ValueError:
self.data = None
raise ValueError(self.gettext('Invalid JSON'))
from flask_admin.form import JSONField
def to_json(self, obj):
return json.dumps(obj)
def from_json(self, data):
return json.loads(data)
from .widgets import LeafletWidget
class GeoJSONField(JSONField):
widget = LeafletWidget()
def __init__(self, label=None, validators=None, geometry_type="GEOMETRY", srid='-1', session=None, **kwargs):
def __init__(self, label=None, validators=None, geometry_type="GEOMETRY",
srid='-1', session=None, **kwargs):
super(GeoJSONField, self).__init__(label, validators, **kwargs)
self.web_srid = 4326
self.srid = srid
......
......@@ -350,6 +350,10 @@ class AdminModelConverter(ModelConverterBase):
inner_form = field_args.pop('form', HstoreForm)
return InlineHstoreList(InlineFormField(inner_form), **field_args)
@converts('JSON')
def convert_JSON(self, field_args, **extra):
return form.JSONField(**field_args)
def _resolve_prop(prop):
"""
......
import time
import datetime
import json
from wtforms import fields, widgets
from wtforms import fields
from flask_admin.babel import gettext
from flask_admin._compat import text_type, as_unicode
......@@ -11,7 +12,8 @@ from . import widgets as admin_widgets
An understanding of WTForms's Custom Widgets is helpful for understanding this code: http://wtforms.simplecodes.com/docs/0.6.2/widgets.html#custom-widgets
"""
__all__ = ['DateTimeField', 'TimeField', 'Select2Field', 'Select2TagsField']
__all__ = ['DateTimeField', 'TimeField', 'Select2Field', 'Select2TagsField',
'JSONField']
class DateTimeField(fields.DateTimeField):
......@@ -176,3 +178,28 @@ class Select2TagsField(fields.StringField):
return as_unicode(self.data)
else:
return u''
class JSONField(fields.TextAreaField):
def _value(self):
if self.raw_data:
return self.raw_data[0]
elif self.data:
# prevent utf8 characters from being converted to ascii
return as_unicode(json.dumps(self.data, ensure_ascii=False))
else:
return ''
def process_formdata(self, valuelist):
if valuelist:
value = valuelist[0]
# allow saving blank field as None
if not value:
self.data = None
return
try:
self.data = json.loads(valuelist[0])
except ValueError:
raise ValueError(self.gettext('Invalid JSON'))
import json
from jinja2 import Markup
from flask_admin._compat import text_type
try:
......@@ -58,15 +60,28 @@ def enum_formatter(view, value):
return value.name
def dict_formatter(view, value):
"""
Removes unicode entities when displaying dict as string. Also unescapes
non-ASCII characters stored in the JSON.
:param value:
Dict to convert to string
"""
return json.dumps(value, ensure_ascii=False)
BASE_FORMATTERS = {
type(None): empty_formatter,
bool: bool_formatter,
list: list_formatter,
dict: dict_formatter,
}
EXPORT_FORMATTERS = {
type(None): empty_formatter,
list: list_formatter,
dict: dict_formatter,
}
if Enum is not None:
......
......@@ -3,7 +3,7 @@ from nose.tools import eq_, ok_
from . import setup_postgres
from .test_basic import CustomModelView
from sqlalchemy.dialects.postgresql import HSTORE
from sqlalchemy.dialects.postgresql import HSTORE, JSON
def test_hstore():
......@@ -40,3 +40,38 @@ def test_hstore():
data = rv.data.decode('utf-8')
ok_('test_val1' in data)
ok_('test_val2' in data)
def test_json():
app, db, admin = setup_postgres()
class JSONModel(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
json_test = db.Column(JSON)
db.create_all()
view = CustomModelView(JSONModel, db.session)
admin.add_view(view)
client = app.test_client()
rv = client.get('/admin/jsonmodel/')
eq_(rv.status_code, 200)
rv = client.post('/admin/jsonmodel/new/', data={
'json_test': '{"test_key1": "test_value1"}',
})
eq_(rv.status_code, 302)
rv = client.get('/admin/jsonmodel/')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('json_test' in data)
ok_('{"test_key1": "test_value1"}' in data)
rv = client.get('/admin/jsonmodel/edit/?id=1')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('json_test' in data)
ok_('>{"test_key1": "test_value1"}<' in data)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment