2021-08-17 17:00:34 +08:00
|
|
|
|
"""Contains the logic to create cohesive forms on the explore view"""
|
2022-10-11 14:25:25 +08:00
|
|
|
|
from flask_appbuilder.fieldwidgets import BS3TextFieldWidget
|
2023-04-06 23:03:18 +08:00
|
|
|
|
from wtforms import Field
|
2023-09-03 21:17:55 +08:00
|
|
|
|
from flask_appbuilder.fieldwidgets import BS3TextFieldWidget, BS3PasswordFieldWidget, DatePickerWidget, DateTimePickerWidget, Select2ManyWidget, Select2Widget
|
2023-04-06 23:03:18 +08:00
|
|
|
|
from wtforms import widgets
|
2021-08-17 17:00:34 +08:00
|
|
|
|
from myapp import app
|
|
|
|
|
|
|
|
|
|
conf = app.config
|
|
|
|
|
|
2023-09-03 21:17:55 +08:00
|
|
|
|
from wtforms.validators import DataRequired, Length, NumberRange, Optional, Regexp, ValidationError
|
|
|
|
|
|
2021-08-17 17:00:34 +08:00
|
|
|
|
# 处理完再校验
|
|
|
|
|
class JsonValidator(object):
|
|
|
|
|
def __init__(self):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def __call__(self, form, field):
|
|
|
|
|
data = field.data
|
|
|
|
|
if data is None:
|
|
|
|
|
raise ValidationError('input must json')
|
|
|
|
|
try:
|
|
|
|
|
json.loads(data)
|
|
|
|
|
except Exception as e:
|
2023-09-03 21:17:55 +08:00
|
|
|
|
raise ValidationError("JSON is not valid :%s" % str(e))
|
|
|
|
|
|
2021-08-17 17:00:34 +08:00
|
|
|
|
|
|
|
|
|
class MyCommaSeparatedListField(Field):
|
|
|
|
|
widget = BS3TextFieldWidget()
|
|
|
|
|
|
|
|
|
|
def _value(self):
|
|
|
|
|
if self.data:
|
|
|
|
|
return u", ".join(self.data)
|
|
|
|
|
else:
|
|
|
|
|
return u""
|
|
|
|
|
|
|
|
|
|
def process_formdata(self, valuelist):
|
|
|
|
|
if valuelist:
|
|
|
|
|
self.data = [x.strip() for x in valuelist[0].split(",")]
|
|
|
|
|
else:
|
|
|
|
|
self.data = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def filter_not_empty_values(value):
|
|
|
|
|
"""Returns a list of non empty values or None"""
|
|
|
|
|
if not value:
|
|
|
|
|
return None
|
|
|
|
|
data = [x for x in value if x]
|
|
|
|
|
if not data:
|
|
|
|
|
return None
|
|
|
|
|
return data
|
|
|
|
|
|
|
|
|
|
|
2023-09-03 21:17:55 +08:00
|
|
|
|
import pysnooper, datetime, time, json
|
2023-12-11 13:25:07 +08:00
|
|
|
|
from wtforms.widgets.core import Markup, html_params
|
2023-04-06 23:03:18 +08:00
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
from html import escape
|
|
|
|
|
except ImportError:
|
|
|
|
|
from cgi import escape
|
|
|
|
|
from wtforms.compat import text_type, iteritems
|
|
|
|
|
|
|
|
|
|
|
2021-08-17 17:00:34 +08:00
|
|
|
|
class MyCodeArea(object):
|
|
|
|
|
def __init__(self, code=''):
|
2023-09-03 21:17:55 +08:00
|
|
|
|
self.code = code
|
|
|
|
|
|
2021-08-17 17:00:34 +08:00
|
|
|
|
def __call__(self, field, **kwargs):
|
|
|
|
|
if self.code:
|
2023-12-11 13:25:07 +08:00
|
|
|
|
return Markup('<pre><code>%s</code></pre>' % (self.code,))
|
2021-08-17 17:00:34 +08:00
|
|
|
|
else:
|
2023-12-11 13:25:07 +08:00
|
|
|
|
return Markup('<pre><code>%s</code></pre>' % (field._value(),))
|
|
|
|
|
# return Markup('<pre><code>%s</code></pre>' % (field._value(),))
|
2021-08-17 17:00:34 +08:00
|
|
|
|
|
2023-09-03 21:17:55 +08:00
|
|
|
|
|
2021-08-17 17:00:34 +08:00
|
|
|
|
from wtforms import widgets
|
2023-09-03 21:17:55 +08:00
|
|
|
|
|
|
|
|
|
|
2021-08-17 17:00:34 +08:00
|
|
|
|
class MyBS3TextAreaFieldWidget(widgets.TextArea):
|
2023-09-03 21:17:55 +08:00
|
|
|
|
def __init__(self, rows=3, readonly=0, expand_filed=None, tips=None): # 扩展成list类型字段
|
|
|
|
|
self.rows = rows
|
2021-08-17 17:00:34 +08:00
|
|
|
|
self.readonly = readonly
|
2023-09-03 21:17:55 +08:00
|
|
|
|
self.expand_filed = expand_filed
|
2023-04-06 23:03:18 +08:00
|
|
|
|
self.tips = tips
|
2021-08-17 17:00:34 +08:00
|
|
|
|
return super(MyBS3TextAreaFieldWidget, self).__init__()
|
2022-08-28 20:24:10 +08:00
|
|
|
|
|
2021-08-17 17:00:34 +08:00
|
|
|
|
def __call__(self, field, **kwargs):
|
|
|
|
|
kwargs["class"] = u"form-control"
|
|
|
|
|
kwargs["rows"] = self.rows
|
|
|
|
|
if field.label:
|
|
|
|
|
kwargs["placeholder"] = field.label.text
|
|
|
|
|
if self.readonly:
|
2023-09-03 21:17:55 +08:00
|
|
|
|
kwargs['readonly'] = 'readonly'
|
2021-08-17 17:00:34 +08:00
|
|
|
|
return super(MyBS3TextAreaFieldWidget, self).__call__(field, **kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MyBS3TextFieldWidget(widgets.TextInput):
|
2023-09-03 21:17:55 +08:00
|
|
|
|
def __init__(self, value='', readonly=0, is_date=False, is_date_range=False):
|
|
|
|
|
self.value = value
|
2021-08-17 17:00:34 +08:00
|
|
|
|
self.readonly = readonly
|
2023-09-03 21:17:55 +08:00
|
|
|
|
self.is_date = is_date
|
|
|
|
|
self.is_date_range = is_date_range
|
2021-08-17 17:00:34 +08:00
|
|
|
|
return super(MyBS3TextFieldWidget, self).__init__()
|
|
|
|
|
|
|
|
|
|
def __call__(self, field, **kwargs):
|
|
|
|
|
kwargs["class"] = u"form-control"
|
|
|
|
|
if field.label:
|
|
|
|
|
kwargs["placeholder"] = field.label.text
|
|
|
|
|
if "name_" in kwargs:
|
|
|
|
|
field.name = kwargs["name_"]
|
|
|
|
|
if self.value:
|
|
|
|
|
kwargs['value'] = self.value
|
|
|
|
|
if self.readonly:
|
2023-09-03 21:17:55 +08:00
|
|
|
|
kwargs['readonly'] = 'readonly'
|
2021-08-17 17:00:34 +08:00
|
|
|
|
return super(MyBS3TextFieldWidget, self).__call__(field, **kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MyLineSeparatedListField(Field):
|
|
|
|
|
widget = MyBS3TextAreaFieldWidget()
|
|
|
|
|
|
|
|
|
|
# 前端要显示的值
|
|
|
|
|
def _value(self):
|
|
|
|
|
if self.data:
|
2023-09-03 21:17:55 +08:00
|
|
|
|
return u"\n".join(self.data) # 数据库里面的数据是list
|
2021-08-17 17:00:34 +08:00
|
|
|
|
else:
|
|
|
|
|
return u""
|
|
|
|
|
|
|
|
|
|
# 发送到后端的值
|
|
|
|
|
def process_formdata(self, valuelist):
|
|
|
|
|
if valuelist:
|
|
|
|
|
self.data = [x.strip() for x in valuelist[0].split("\n")]
|
|
|
|
|
else:
|
|
|
|
|
self.data = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MyJSONField(Field):
|
|
|
|
|
widget = MyBS3TextAreaFieldWidget(rows=3)
|
|
|
|
|
|
|
|
|
|
# 前端要显示的值
|
|
|
|
|
def _value(self):
|
|
|
|
|
if self.data:
|
|
|
|
|
# return self.data #
|
2023-09-03 21:17:55 +08:00
|
|
|
|
if type(self.data) == str: # 如果是字符集就原样返回
|
2021-08-17 17:00:34 +08:00
|
|
|
|
return self.data
|
2023-09-03 21:17:55 +08:00
|
|
|
|
return json.dumps(self.data, indent=4, ensure_ascii=False) # 数据库里面的数据是list
|
2021-08-17 17:00:34 +08:00
|
|
|
|
else:
|
|
|
|
|
return u"{}"
|
|
|
|
|
|
|
|
|
|
# # 后端发送前端时的数据处理,处理完以后使用_value()进行显示
|
|
|
|
|
# @pysnooper.snoop()
|
|
|
|
|
# def process_data(self, value):
|
|
|
|
|
# try:
|
|
|
|
|
# if value:
|
|
|
|
|
# self.data = json.loads(value)
|
|
|
|
|
# else:
|
|
|
|
|
# self.data = {}
|
|
|
|
|
# except Exception as e:
|
|
|
|
|
# self.data={}
|
|
|
|
|
# print(self.data,type(self.data))
|
|
|
|
|
|
|
|
|
|
# 发送到后端的值
|
|
|
|
|
def process_formdata(self, valuelist):
|
|
|
|
|
try:
|
|
|
|
|
if valuelist:
|
|
|
|
|
self.data = json.loads(valuelist[0])
|
|
|
|
|
else:
|
|
|
|
|
self.data = {}
|
|
|
|
|
except Exception as e:
|
2023-09-03 21:17:55 +08:00
|
|
|
|
self.data = valuelist[0] # self.default # 如果出错,self.data就是原始字符串了。
|
|
|
|
|
raise ValidationError('input must json:' + str(e))
|
2021-08-17 17:00:34 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from wtforms.widgets.core import escape_html
|
|
|
|
|
from flask_babel import lazy_gettext as _
|
|
|
|
|
|
|
|
|
|
|
2023-09-03 21:17:55 +08:00
|
|
|
|
class MySelect2Widget(object):
|
2021-08-17 17:00:34 +08:00
|
|
|
|
extra_classes = None
|
|
|
|
|
|
2023-09-03 21:17:55 +08:00
|
|
|
|
def __init__(self, extra_classes=None, style=None, multiple=False, new_web=True, value='', can_input=False, conten2choices=False, retry_info=False):
|
2021-08-17 17:00:34 +08:00
|
|
|
|
self.extra_classes = extra_classes
|
|
|
|
|
self.style = style or u"width:350px"
|
|
|
|
|
self.multiple = multiple
|
2023-09-03 21:17:55 +08:00
|
|
|
|
self.value = value
|
|
|
|
|
self.new_web = new_web
|
2022-05-31 14:16:55 +08:00
|
|
|
|
self.can_input = can_input
|
2023-09-03 21:17:55 +08:00
|
|
|
|
self.conten2choices = conten2choices
|
|
|
|
|
self.retry_info = retry_info
|
2021-08-17 17:00:34 +08:00
|
|
|
|
|
|
|
|
|
# @pysnooper.snoop()
|
|
|
|
|
def __call__(self, field, **kwargs):
|
|
|
|
|
kwargs["class"] = u"my_select2 form-control"
|
|
|
|
|
if self.extra_classes:
|
|
|
|
|
kwargs["class"] = kwargs["class"] + " " + self.extra_classes
|
|
|
|
|
kwargs["style"] = self.style
|
|
|
|
|
kwargs["data-placeholder"] = _("Select Value")
|
|
|
|
|
if "name_" in kwargs:
|
|
|
|
|
field.name = kwargs["name_"]
|
|
|
|
|
|
|
|
|
|
kwargs.setdefault('id', field.id)
|
|
|
|
|
if self.multiple:
|
|
|
|
|
kwargs['multiple'] = True
|
|
|
|
|
if 'required' not in kwargs and 'required' in getattr(field, 'flags', []):
|
|
|
|
|
kwargs['required'] = True
|
|
|
|
|
if self.new_web:
|
2023-09-03 21:17:55 +08:00
|
|
|
|
fun = "set_change('%s')" % field.name
|
2021-08-17 17:00:34 +08:00
|
|
|
|
else:
|
2023-09-03 21:17:55 +08:00
|
|
|
|
fun = ''
|
2021-08-17 17:00:34 +08:00
|
|
|
|
|
|
|
|
|
html = ['''<select %s id=%s onchange="%s">''' %
|
2023-09-03 21:17:55 +08:00
|
|
|
|
(html_params(name=field.name, **kwargs), field.name, fun)]
|
2021-08-17 17:00:34 +08:00
|
|
|
|
for val, label, selected in field.iter_choices():
|
|
|
|
|
if self.value:
|
2023-09-03 21:17:55 +08:00
|
|
|
|
if str(val) == str(self.value):
|
2021-08-17 17:00:34 +08:00
|
|
|
|
html.append(self.render_option(val, label, selected=True))
|
|
|
|
|
else:
|
|
|
|
|
html.append(self.render_option(val, label, selected=False))
|
|
|
|
|
else:
|
|
|
|
|
html.append(self.render_option(val, label, selected))
|
|
|
|
|
html.append('</select>')
|
2023-12-11 13:25:07 +08:00
|
|
|
|
return Markup(''.join(html))
|
2021-08-17 17:00:34 +08:00
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def render_option(cls, value, label, selected, **kwargs):
|
|
|
|
|
if value is True:
|
|
|
|
|
# Handle the special case of a 'True' value.
|
|
|
|
|
value = text_type(value)
|
|
|
|
|
|
|
|
|
|
options = dict(kwargs, value=value)
|
|
|
|
|
if selected:
|
|
|
|
|
options['selected'] = True
|
2023-12-11 13:25:07 +08:00
|
|
|
|
return Markup('<option %s>%s</option>' % (html_params(**options), escape_html(label, quote=False)))
|
2021-08-17 17:00:34 +08:00
|
|
|
|
|
2023-09-03 21:17:55 +08:00
|
|
|
|
|
2021-08-17 17:00:34 +08:00
|
|
|
|
# json编辑框
|
|
|
|
|
class MyJsonIde(object):
|
|
|
|
|
def __call__(self, field, **kwargs):
|
2023-12-11 13:25:07 +08:00
|
|
|
|
return Markup('<pre><code>%s</code></pre>' % (field._value(),))
|
|
|
|
|
# return Markup('<pre><code>%s</code></pre>' % (field._value(),))
|
2021-08-17 17:00:34 +08:00
|
|
|
|
|
|
|
|
|
|
2022-05-31 14:16:55 +08:00
|
|
|
|
class MySelect2ManyWidget(widgets.Select):
|
|
|
|
|
extra_classes = None
|
|
|
|
|
|
2023-09-03 21:17:55 +08:00
|
|
|
|
def __init__(self, extra_classes=None, style=None, can_input=False):
|
2022-05-31 14:16:55 +08:00
|
|
|
|
self.extra_classes = extra_classes
|
|
|
|
|
self.style = style or u"width:250px"
|
2023-09-03 21:17:55 +08:00
|
|
|
|
self.can_input = can_input
|
2022-05-31 14:16:55 +08:00
|
|
|
|
return super(MySelect2ManyWidget, self).__init__()
|
|
|
|
|
|
2021-08-17 17:00:34 +08:00
|
|
|
|
|
|
|
|
|
from wtforms.fields.core import SelectField
|
2023-09-03 21:17:55 +08:00
|
|
|
|
|
|
|
|
|
|
2021-08-17 17:00:34 +08:00
|
|
|
|
class MySelectMultipleField(SelectField):
|
|
|
|
|
"""
|
|
|
|
|
No different from a normal select field, except this one can take (and
|
|
|
|
|
validate) multiple choices. You'll need to specify the HTML `size`
|
|
|
|
|
attribute to the select field when rendering.
|
|
|
|
|
"""
|
|
|
|
|
widget = widgets.Select(multiple=True)
|
|
|
|
|
|
|
|
|
|
def iter_choices(self):
|
|
|
|
|
for value, label in self.choices:
|
|
|
|
|
selected = self.data is not None and self.coerce(value) in self.data
|
|
|
|
|
yield (value, label, selected)
|
|
|
|
|
|
|
|
|
|
# 将数据库数据处理成前端需要的数据.post的时候也会调用一遍,那时value为None
|
|
|
|
|
# @pysnooper.snoop(watch_explode='value')
|
|
|
|
|
def process_data(self, value):
|
|
|
|
|
try:
|
|
|
|
|
if value:
|
|
|
|
|
self.data = list(self.coerce(v) for v in value.split(','))
|
2023-09-03 21:17:55 +08:00
|
|
|
|
self.data = [x for x in self.data if x]
|
2021-08-17 17:00:34 +08:00
|
|
|
|
# print(self.data)
|
|
|
|
|
else:
|
2023-09-03 21:17:55 +08:00
|
|
|
|
self.data = None
|
2021-08-17 17:00:34 +08:00
|
|
|
|
except (ValueError, TypeError):
|
|
|
|
|
self.data = None
|
|
|
|
|
|
|
|
|
|
# @pysnooper.snoop(watch_explode='valuelist')
|
|
|
|
|
def process_formdata(self, valuelist):
|
|
|
|
|
try:
|
|
|
|
|
self.data = ','.join(list(self.coerce(x) for x in valuelist))
|
|
|
|
|
# print(self.data)
|
|
|
|
|
except ValueError:
|
|
|
|
|
raise ValueError(self.gettext('Invalid choice(s): one or more data inputs could not be coerced'))
|
|
|
|
|
|
|
|
|
|
def pre_validate(self, form):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from flask_appbuilder.widgets import FormWidget
|
|
|
|
|
from flask_appbuilder._compat import as_unicode
|
|
|
|
|
|
2023-09-03 21:17:55 +08:00
|
|
|
|
|
2021-08-17 17:00:34 +08:00
|
|
|
|
class MySearchWidget(FormWidget):
|
|
|
|
|
template = "appbuilder/general/widgets/search.html"
|
|
|
|
|
filters = None
|
|
|
|
|
|
|
|
|
|
def __init__(self, **kwargs):
|
|
|
|
|
self.filters = kwargs.get("filters")
|
2023-09-03 21:17:55 +08:00
|
|
|
|
self.help_url = kwargs.get("help_url", '')
|
2021-08-17 17:00:34 +08:00
|
|
|
|
return super(MySearchWidget, self).__init__(**kwargs)
|
|
|
|
|
|
|
|
|
|
def __call__(self, **kwargs):
|
|
|
|
|
""" create dict labels based on form """
|
|
|
|
|
""" create dict of form widgets """
|
|
|
|
|
""" create dict of possible filters """
|
|
|
|
|
""" create list of active filters """
|
|
|
|
|
label_columns = {}
|
|
|
|
|
form_fields = {}
|
|
|
|
|
search_filters = {}
|
|
|
|
|
dict_filters = self.filters.get_search_filters()
|
|
|
|
|
for col in self.template_args["include_cols"]:
|
|
|
|
|
label_columns[col] = as_unicode(self.template_args["form"][col].label.text)
|
|
|
|
|
form_fields[col] = self.template_args["form"][col]()
|
|
|
|
|
search_filters[col] = [as_unicode(flt.name) for flt in dict_filters[col]]
|
|
|
|
|
|
|
|
|
|
kwargs["help_url"] = self.help_url
|
|
|
|
|
kwargs["label_columns"] = label_columns
|
|
|
|
|
kwargs["form_fields"] = form_fields
|
|
|
|
|
kwargs["search_filters"] = search_filters
|
|
|
|
|
kwargs["active_filters"] = self.filters.get_filters_values_tojson()
|
|
|
|
|
return super(MySearchWidget, self).__call__(**kwargs)
|