flask-appbuilder 3.2.1rc1__py3-none-any.whl → 5.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (228) hide show
  1. flask_appbuilder/__init__.py +2 -3
  2. flask_appbuilder/_compat.py +0 -1
  3. flask_appbuilder/actions.py +14 -14
  4. flask_appbuilder/api/__init__.py +741 -527
  5. flask_appbuilder/api/convert.py +104 -98
  6. flask_appbuilder/api/manager.py +14 -8
  7. flask_appbuilder/api/schemas.py +12 -1
  8. flask_appbuilder/babel/manager.py +12 -16
  9. flask_appbuilder/base.py +353 -280
  10. flask_appbuilder/basemanager.py +1 -1
  11. flask_appbuilder/baseviews.py +241 -164
  12. flask_appbuilder/charts/jsontools.py +10 -10
  13. flask_appbuilder/charts/views.py +56 -60
  14. flask_appbuilder/cli.py +115 -70
  15. flask_appbuilder/const.py +52 -52
  16. flask_appbuilder/exceptions.py +67 -5
  17. flask_appbuilder/fields.py +32 -23
  18. flask_appbuilder/fieldwidgets.py +34 -27
  19. flask_appbuilder/filemanager.py +33 -45
  20. flask_appbuilder/filters.py +11 -13
  21. flask_appbuilder/forms.py +31 -35
  22. flask_appbuilder/hooks.py +90 -0
  23. flask_appbuilder/menu.py +35 -10
  24. flask_appbuilder/models/base.py +47 -57
  25. flask_appbuilder/models/decorators.py +13 -13
  26. flask_appbuilder/models/filters.py +42 -38
  27. flask_appbuilder/models/generic/__init__.py +29 -29
  28. flask_appbuilder/models/generic/filters.py +11 -3
  29. flask_appbuilder/models/generic/interface.py +1 -3
  30. flask_appbuilder/models/group.py +37 -39
  31. flask_appbuilder/models/mixins.py +22 -18
  32. flask_appbuilder/models/sqla/__init__.py +19 -72
  33. flask_appbuilder/models/sqla/base.py +24 -0
  34. flask_appbuilder/models/sqla/base_legacy.py +132 -0
  35. flask_appbuilder/models/sqla/filters.py +132 -19
  36. flask_appbuilder/models/sqla/interface.py +390 -276
  37. flask_appbuilder/security/api.py +31 -35
  38. flask_appbuilder/security/decorators.py +181 -83
  39. flask_appbuilder/security/forms.py +20 -31
  40. flask_appbuilder/security/manager.py +715 -489
  41. flask_appbuilder/security/registerviews.py +29 -112
  42. flask_appbuilder/security/schemas.py +43 -0
  43. flask_appbuilder/security/sqla/apis/__init__.py +8 -0
  44. flask_appbuilder/security/sqla/apis/group/__init__.py +1 -0
  45. flask_appbuilder/security/sqla/apis/group/api.py +227 -0
  46. flask_appbuilder/security/sqla/apis/group/schema.py +73 -0
  47. flask_appbuilder/security/sqla/apis/permission/__init__.py +1 -0
  48. flask_appbuilder/security/sqla/apis/permission/api.py +19 -0
  49. flask_appbuilder/security/sqla/apis/permission_view_menu/__init__.py +1 -0
  50. flask_appbuilder/security/sqla/apis/permission_view_menu/api.py +16 -0
  51. flask_appbuilder/security/sqla/apis/role/__init__.py +1 -0
  52. flask_appbuilder/security/sqla/apis/role/api.py +306 -0
  53. flask_appbuilder/security/sqla/apis/role/schema.py +27 -0
  54. flask_appbuilder/security/sqla/apis/user/__init__.py +1 -0
  55. flask_appbuilder/security/sqla/apis/user/api.py +292 -0
  56. flask_appbuilder/security/sqla/apis/user/schema.py +97 -0
  57. flask_appbuilder/security/sqla/apis/user/validator.py +27 -0
  58. flask_appbuilder/security/sqla/apis/view_menu/__init__.py +1 -0
  59. flask_appbuilder/security/sqla/apis/view_menu/api.py +18 -0
  60. flask_appbuilder/security/sqla/manager.py +421 -203
  61. flask_appbuilder/security/sqla/models.py +192 -57
  62. flask_appbuilder/security/utils.py +9 -0
  63. flask_appbuilder/security/views.py +232 -229
  64. flask_appbuilder/static/.DS_Store +0 -0
  65. flask_appbuilder/static/appbuilder/css/ab.css +20 -12
  66. flask_appbuilder/static/appbuilder/css/bootstrap-datepicker/bootstrap-datepicker3.min.css +7 -0
  67. flask_appbuilder/static/appbuilder/css/bootstrap.min.css.map +1 -0
  68. flask_appbuilder/static/appbuilder/css/flags/flags16.css +249 -245
  69. flask_appbuilder/static/appbuilder/css/fontawesome/all.min.css +6 -0
  70. flask_appbuilder/static/appbuilder/css/fontawesome/brands.min.css +6 -0
  71. flask_appbuilder/static/appbuilder/css/fontawesome/fontawesome.min.css +6 -0
  72. flask_appbuilder/static/appbuilder/css/fontawesome/regular.min.css +6 -0
  73. flask_appbuilder/static/appbuilder/css/fontawesome/solid.min.css +6 -0
  74. flask_appbuilder/static/appbuilder/css/fontawesome/svg-with-js.min.css +6 -0
  75. flask_appbuilder/static/appbuilder/css/fontawesome/v4-font-face.min.css +6 -0
  76. flask_appbuilder/static/appbuilder/css/fontawesome/v4-shims.min.css +6 -0
  77. flask_appbuilder/static/appbuilder/css/fontawesome/v5-font-face.min.css +6 -0
  78. flask_appbuilder/static/appbuilder/css/images/flags16.png +0 -0
  79. flask_appbuilder/static/appbuilder/css/select2/select2-bootstrap.min.css +7 -0
  80. flask_appbuilder/static/appbuilder/css/select2/select2.min.css +1 -0
  81. flask_appbuilder/static/appbuilder/css/swagger/swagger-ui.css +3 -0
  82. flask_appbuilder/static/appbuilder/css/webfonts/fa-brands-400.ttf +0 -0
  83. flask_appbuilder/static/appbuilder/css/webfonts/fa-brands-400.woff2 +0 -0
  84. flask_appbuilder/static/appbuilder/css/webfonts/fa-regular-400.ttf +0 -0
  85. flask_appbuilder/static/appbuilder/css/webfonts/fa-regular-400.woff2 +0 -0
  86. flask_appbuilder/static/appbuilder/css/webfonts/fa-solid-900.ttf +0 -0
  87. flask_appbuilder/static/appbuilder/css/webfonts/fa-solid-900.woff2 +0 -0
  88. flask_appbuilder/static/appbuilder/css/webfonts/fa-v4compatibility.ttf +0 -0
  89. flask_appbuilder/static/appbuilder/css/webfonts/fa-v4compatibility.woff2 +0 -0
  90. flask_appbuilder/static/appbuilder/js/ab.js +33 -23
  91. flask_appbuilder/static/appbuilder/js/ab_filters.js +91 -84
  92. flask_appbuilder/static/appbuilder/js/bootstrap-datepicker/bootstrap-datepicker.min.js +8 -0
  93. flask_appbuilder/static/appbuilder/js/jquery-latest.js +2 -2
  94. flask_appbuilder/static/appbuilder/js/select2/select2.min.js +2 -0
  95. flask_appbuilder/static/appbuilder/js/swagger-ui-bundle.js +3 -0
  96. flask_appbuilder/templates/appbuilder/baselib.html +9 -3
  97. flask_appbuilder/templates/appbuilder/general/lib.html +60 -34
  98. flask_appbuilder/templates/appbuilder/general/model/edit.html +1 -1
  99. flask_appbuilder/templates/appbuilder/general/model/edit_cascade.html +1 -1
  100. flask_appbuilder/templates/appbuilder/general/model/search.html +3 -2
  101. flask_appbuilder/templates/appbuilder/general/model/show.html +1 -1
  102. flask_appbuilder/templates/appbuilder/general/model/show_cascade.html +1 -1
  103. flask_appbuilder/templates/appbuilder/general/security/login_db.html +7 -7
  104. flask_appbuilder/templates/appbuilder/general/security/login_ldap.html +5 -5
  105. flask_appbuilder/templates/appbuilder/general/security/login_oauth.html +24 -49
  106. flask_appbuilder/templates/appbuilder/general/widgets/base_list.html +2 -1
  107. flask_appbuilder/templates/appbuilder/general/widgets/chart.html +4 -2
  108. flask_appbuilder/templates/appbuilder/general/widgets/direct_chart.html +4 -3
  109. flask_appbuilder/templates/appbuilder/general/widgets/multiple_chart.html +3 -2
  110. flask_appbuilder/templates/appbuilder/general/widgets/search.html +11 -10
  111. flask_appbuilder/templates/appbuilder/init.html +37 -43
  112. flask_appbuilder/templates/appbuilder/navbar_menu.html +1 -1
  113. flask_appbuilder/templates/appbuilder/navbar_right.html +2 -2
  114. flask_appbuilder/templates/appbuilder/swagger/swagger.html +22 -19
  115. flask_appbuilder/translations/de/LC_MESSAGES/messages.mo +0 -0
  116. flask_appbuilder/translations/de/LC_MESSAGES/messages.po +305 -161
  117. flask_appbuilder/translations/fa/LC_MESSAGES/messages.mo +0 -0
  118. flask_appbuilder/translations/fa/LC_MESSAGES/messages.po +802 -0
  119. flask_appbuilder/translations/fr/LC_MESSAGES/messages.po +461 -319
  120. flask_appbuilder/translations/pt_BR/LC_MESSAGES/messages.po +650 -650
  121. flask_appbuilder/translations/ru/LC_MESSAGES/messages.po +1 -1
  122. flask_appbuilder/translations/sl/LC_MESSAGES/messages.mo +0 -0
  123. flask_appbuilder/translations/sl/LC_MESSAGES/messages.po +690 -0
  124. flask_appbuilder/translations/tr/LC_MESSAGES/messages.mo +0 -0
  125. flask_appbuilder/translations/tr/LC_MESSAGES/messages.po +1015 -0
  126. flask_appbuilder/upload.py +20 -22
  127. flask_appbuilder/urltools.py +39 -19
  128. flask_appbuilder/utils/base.py +76 -0
  129. flask_appbuilder/utils/legacy.py +33 -0
  130. flask_appbuilder/utils/limit.py +20 -0
  131. flask_appbuilder/validators.py +73 -14
  132. flask_appbuilder/views.py +75 -424
  133. flask_appbuilder/widgets.py +50 -51
  134. {Flask_AppBuilder-3.2.1rc1.dist-info → flask_appbuilder-5.0.2.dist-info}/METADATA +36 -76
  135. flask_appbuilder-5.0.2.dist-info/RECORD +240 -0
  136. {Flask_AppBuilder-3.2.1rc1.dist-info → flask_appbuilder-5.0.2.dist-info}/WHEEL +1 -1
  137. flask_appbuilder-5.0.2.dist-info/entry_points.txt +2 -0
  138. Flask_AppBuilder-3.2.1rc1.dist-info/RECORD +0 -270
  139. Flask_AppBuilder-3.2.1rc1.dist-info/entry_points.txt +0 -6
  140. flask_appbuilder/console.py +0 -426
  141. flask_appbuilder/models/mongoengine/__init__.py +0 -0
  142. flask_appbuilder/models/mongoengine/fields.py +0 -65
  143. flask_appbuilder/models/mongoengine/filters.py +0 -145
  144. flask_appbuilder/models/mongoengine/interface.py +0 -328
  145. flask_appbuilder/security/mongoengine/__init__.py +0 -0
  146. flask_appbuilder/security/mongoengine/manager.py +0 -402
  147. flask_appbuilder/security/mongoengine/models.py +0 -120
  148. flask_appbuilder/static/appbuilder/css/font-awesome.min.css +0 -4
  149. flask_appbuilder/static/appbuilder/datepicker/bootstrap-datepicker.css +0 -9
  150. flask_appbuilder/static/appbuilder/datepicker/bootstrap-datepicker.js +0 -28
  151. flask_appbuilder/static/appbuilder/fonts/FontAwesome.otf +0 -0
  152. flask_appbuilder/static/appbuilder/fonts/fontawesome-webfont.eot +0 -0
  153. flask_appbuilder/static/appbuilder/fonts/fontawesome-webfont.svg +0 -2671
  154. flask_appbuilder/static/appbuilder/fonts/fontawesome-webfont.ttf +0 -0
  155. flask_appbuilder/static/appbuilder/fonts/fontawesome-webfont.woff +0 -0
  156. flask_appbuilder/static/appbuilder/fonts/fontawesome-webfont.woff2 +0 -0
  157. flask_appbuilder/static/appbuilder/img/aol.png +0 -0
  158. flask_appbuilder/static/appbuilder/img/flags/flags16.png +0 -0
  159. flask_appbuilder/static/appbuilder/img/flickr.png +0 -0
  160. flask_appbuilder/static/appbuilder/img/google.png +0 -0
  161. flask_appbuilder/static/appbuilder/img/myopenid.png +0 -0
  162. flask_appbuilder/static/appbuilder/img/yahoo.png +0 -0
  163. flask_appbuilder/static/appbuilder/js/_google_charts.js +0 -39
  164. flask_appbuilder/static/appbuilder/js/html5shiv.js +0 -8
  165. flask_appbuilder/static/appbuilder/js/respond.min.js +0 -6
  166. flask_appbuilder/static/appbuilder/select2/select2-spinner.gif +0 -0
  167. flask_appbuilder/static/appbuilder/select2/select2.css +0 -1205
  168. flask_appbuilder/static/appbuilder/select2/select2.js +0 -23
  169. flask_appbuilder/static/appbuilder/select2/select2.png +0 -0
  170. flask_appbuilder/static/appbuilder/select2/select2x2.png +0 -0
  171. flask_appbuilder/templates/appbuilder/general/security/login_oid.html +0 -129
  172. flask_appbuilder/templates/appbuilder/general/security/resetpassword.html +0 -29
  173. flask_appbuilder/tests/__init__.py +0 -0
  174. flask_appbuilder/tests/__pycache__/__init__.cpython-36.pyc +0 -0
  175. flask_appbuilder/tests/__pycache__/__init__.cpython-37.pyc +0 -0
  176. flask_appbuilder/tests/__pycache__/_test_auth_ldap.cpython-37.pyc +0 -0
  177. flask_appbuilder/tests/__pycache__/_test_auth_oauth.cpython-37.pyc +0 -0
  178. flask_appbuilder/tests/__pycache__/_test_ldapsearch.cpython-36.pyc +0 -0
  179. flask_appbuilder/tests/__pycache__/_test_oauth_registration_role.cpython-36.pyc +0 -0
  180. flask_appbuilder/tests/__pycache__/base.cpython-36.pyc +0 -0
  181. flask_appbuilder/tests/__pycache__/base.cpython-37.pyc +0 -0
  182. flask_appbuilder/tests/__pycache__/config_api.cpython-36.pyc +0 -0
  183. flask_appbuilder/tests/__pycache__/config_api.cpython-37.pyc +0 -0
  184. flask_appbuilder/tests/__pycache__/const.cpython-36.pyc +0 -0
  185. flask_appbuilder/tests/__pycache__/const.cpython-37.pyc +0 -0
  186. flask_appbuilder/tests/__pycache__/test_0_fixture.cpython-36.pyc +0 -0
  187. flask_appbuilder/tests/__pycache__/test_0_fixture.cpython-37.pyc +0 -0
  188. flask_appbuilder/tests/__pycache__/test_api.cpython-36.pyc +0 -0
  189. flask_appbuilder/tests/__pycache__/test_api.cpython-37.pyc +0 -0
  190. flask_appbuilder/tests/__pycache__/test_fab_cli.cpython-36.pyc +0 -0
  191. flask_appbuilder/tests/__pycache__/test_fab_cli.cpython-37.pyc +0 -0
  192. flask_appbuilder/tests/__pycache__/test_menu.cpython-36.pyc +0 -0
  193. flask_appbuilder/tests/__pycache__/test_menu.cpython-37.pyc +0 -0
  194. flask_appbuilder/tests/__pycache__/test_mongoengine.cpython-36.pyc +0 -0
  195. flask_appbuilder/tests/__pycache__/test_mvc.cpython-36.pyc +0 -0
  196. flask_appbuilder/tests/__pycache__/test_mvc.cpython-37.pyc +0 -0
  197. flask_appbuilder/tests/__pycache__/test_sqlalchemy.cpython-36.pyc +0 -0
  198. flask_appbuilder/tests/__pycache__/test_sqlalchemy.cpython-37.pyc +0 -0
  199. flask_appbuilder/tests/_test_auth_ldap.py +0 -1045
  200. flask_appbuilder/tests/_test_auth_oauth.py +0 -419
  201. flask_appbuilder/tests/_test_ldapsearch.py +0 -135
  202. flask_appbuilder/tests/_test_oauth_registration_role.py +0 -59
  203. flask_appbuilder/tests/app.db +0 -0
  204. flask_appbuilder/tests/base.py +0 -90
  205. flask_appbuilder/tests/config_api.py +0 -21
  206. flask_appbuilder/tests/const.py +0 -9
  207. flask_appbuilder/tests/mongoengine/__init__.py +0 -0
  208. flask_appbuilder/tests/mongoengine/__pycache__/__init__.cpython-36.pyc +0 -0
  209. flask_appbuilder/tests/mongoengine/__pycache__/__init__.cpython-37.pyc +0 -0
  210. flask_appbuilder/tests/mongoengine/__pycache__/models.cpython-36.pyc +0 -0
  211. flask_appbuilder/tests/mongoengine/models.py +0 -41
  212. flask_appbuilder/tests/sqla/__init__.py +0 -0
  213. flask_appbuilder/tests/sqla/__pycache__/__init__.cpython-36.pyc +0 -0
  214. flask_appbuilder/tests/sqla/__pycache__/__init__.cpython-37.pyc +0 -0
  215. flask_appbuilder/tests/sqla/__pycache__/models.cpython-36.pyc +0 -0
  216. flask_appbuilder/tests/sqla/__pycache__/models.cpython-37.pyc +0 -0
  217. flask_appbuilder/tests/sqla/models.py +0 -340
  218. flask_appbuilder/tests/test_0_fixture.py +0 -39
  219. flask_appbuilder/tests/test_api.py +0 -2790
  220. flask_appbuilder/tests/test_fab_cli.py +0 -72
  221. flask_appbuilder/tests/test_menu.py +0 -122
  222. flask_appbuilder/tests/test_mongoengine.py +0 -572
  223. flask_appbuilder/tests/test_mvc.py +0 -1710
  224. flask_appbuilder/tests/test_sqlalchemy.py +0 -24
  225. flask_appbuilder/translations/__pycache__/__init__.cpython-36.pyc +0 -0
  226. flask_appbuilder/translations/es/LC_MESSAGES/messages.po~ +0 -582
  227. {Flask_AppBuilder-3.2.1rc1.dist-info → flask_appbuilder-5.0.2.dist-info}/LICENSE +0 -0
  228. {Flask_AppBuilder-3.2.1rc1.dist-info → flask_appbuilder-5.0.2.dist-info}/top_level.txt +0 -0
@@ -2,9 +2,15 @@ import datetime
2
2
  import logging
3
3
 
4
4
  from dateutil import parser
5
+ from flask import current_app
6
+ from flask_appbuilder.exceptions import ApplyFilterException
7
+ from flask_appbuilder.models.filters import (
8
+ BaseFilter,
9
+ BaseFilterConverter,
10
+ FilterRelation,
11
+ )
5
12
  from flask_babel import lazy_gettext
6
-
7
- from ..filters import BaseFilter, BaseFilterConverter, FilterRelation
13
+ from sqlalchemy.exc import SQLAlchemyError
8
14
 
9
15
  log = logging.getLogger(__name__)
10
16
 
@@ -15,11 +21,14 @@ __all__ = [
15
21
  "FilterNotStartsWith",
16
22
  "FilterStartsWith",
17
23
  "FilterContains",
24
+ "FilterNotContains",
18
25
  "FilterNotEqual",
19
26
  "FilterEndsWith",
20
27
  "FilterEqualFunction",
21
28
  "FilterGreater",
22
29
  "FilterNotEndsWith",
30
+ "FilterIn",
31
+ "FilterNotIn",
23
32
  "FilterRelationManyToManyEqual",
24
33
  "FilterRelationOneToManyEqual",
25
34
  "FilterRelationOneToManyNotEqual",
@@ -29,13 +38,13 @@ __all__ = [
29
38
 
30
39
  def get_field_setup_query(query, model, column_name):
31
40
  """
32
- Help function for SQLA filters, checks for dot notation on column names.
33
- If it exists, will join the query with the model
34
- from the first part of the field name.
41
+ Help function for SQLA filters, checks for dot notation on column names.
42
+ If it exists, will join the query with the model
43
+ from the first part of the field name.
35
44
 
36
- example:
37
- Contact.created_by: if created_by is a User model,
38
- it will be joined to the query.
45
+ example:
46
+ Contact.created_by: if created_by is a User model,
47
+ it will be joined to the query.
39
48
  """
40
49
  if not hasattr(model, column_name):
41
50
  # it's an inner obj attr
@@ -72,6 +81,9 @@ def set_value_to_type(datamodel, column_name, value):
72
81
  return parser.parse(value)
73
82
  except Exception:
74
83
  return None
84
+ elif datamodel.is_json(column_name):
85
+ # For JSON columns, treat as string for filtering
86
+ return str(value)
75
87
  return value
76
88
 
77
89
 
@@ -178,13 +190,46 @@ class FilterSmaller(BaseFilter):
178
190
  return query.filter(field < value)
179
191
 
180
192
 
193
+ class FilterIn(BaseFilter):
194
+ name = lazy_gettext("In")
195
+ arg_name = "in"
196
+
197
+ def apply(self, query, value):
198
+ query, field = get_field_setup_query(query, self.model, self.column_name)
199
+ typed_values = [
200
+ set_value_to_type(self.datamodel, self.column_name, v) for v in value
201
+ ]
202
+ return query.filter(field.in_(typed_values))
203
+
204
+
205
+ class FilterNotIn(BaseFilter):
206
+ name = lazy_gettext("Not In")
207
+ arg_name = "not_in"
208
+
209
+ def apply(self, query, value):
210
+ query, field = get_field_setup_query(query, self.model, self.column_name)
211
+ typed_values = [
212
+ set_value_to_type(self.datamodel, self.column_name, v) for v in value
213
+ ]
214
+ return query.filter(~field.in_(typed_values))
215
+
216
+
181
217
  class FilterRelationOneToManyEqual(FilterRelation):
182
218
  name = lazy_gettext("Relation")
183
219
  arg_name = "rel_o_m"
184
220
 
185
221
  def apply(self, query, value):
186
222
  query, field = get_field_setup_query(query, self.model, self.column_name)
187
- rel_obj = self.datamodel.get_related_obj(self.column_name, value)
223
+ try:
224
+ rel_obj = self.datamodel.get_related_obj(self.column_name, value)
225
+ except SQLAlchemyError as exc:
226
+ logging.warning("Filter exception for %s will not apply", field)
227
+ try:
228
+ current_app.appbuilder.session.rollback()
229
+ except SQLAlchemyError:
230
+ # on MSSQL a rollback would fail here
231
+ pass
232
+ raise ApplyFilterException(exception=exc)
188
233
  return query.filter(field == rel_obj)
189
234
 
190
235
 
@@ -194,7 +239,16 @@ class FilterRelationOneToManyNotEqual(FilterRelation):
194
239
 
195
240
  def apply(self, query, value):
196
241
  query, field = get_field_setup_query(query, self.model, self.column_name)
197
- rel_obj = self.datamodel.get_related_obj(self.column_name, value)
242
+ try:
243
+ rel_obj = self.datamodel.get_related_obj(self.column_name, value)
244
+ except SQLAlchemyError as exc:
245
+ log.warning("Filter exception for %s will not apply", field)
246
+ try:
247
+ current_app.appbuilder.session.rollback()
248
+ except SQLAlchemyError:
249
+ # on MSSQL a rollback would fail here
250
+ pass
251
+ raise ApplyFilterException(exception=exc)
198
252
  return query.filter(field != rel_obj)
199
253
 
200
254
 
@@ -207,15 +261,27 @@ class FilterRelationManyToManyEqual(FilterRelation):
207
261
  Get object by column_name and value_item, then apply filter if object exists
208
262
  Query with new filter applied
209
263
  """
210
- rel_obj = self.datamodel.get_related_obj(self.column_name, value_item)
264
+ try:
265
+ rel_obj = self.datamodel.get_related_obj(self.column_name, value_item)
266
+ except SQLAlchemyError as exc:
267
+ logging.warning(
268
+ "Filter exception for %s with value %s, will not apply",
269
+ field,
270
+ value_item,
271
+ )
272
+ try:
273
+ current_app.appbuilder.session.rollback()
274
+ except SQLAlchemyError:
275
+ # on MSSQL a rollback would fail here
276
+ pass
277
+ raise ApplyFilterException(exception=exc)
211
278
 
212
279
  if rel_obj:
213
280
  return query.filter(field.contains(rel_obj))
214
281
  else:
215
- log.error(
216
- "Related object for column: %s, value: %s return Null",
282
+ log.warning(
283
+ "Related object for column: %s returned Null",
217
284
  self.column_name,
218
- value_item,
219
285
  )
220
286
 
221
287
  return query
@@ -251,8 +317,8 @@ class FilterInFunction(BaseFilter):
251
317
 
252
318
  class SQLAFilterConverter(BaseFilterConverter):
253
319
  """
254
- Class for converting columns into a supported list of filters
255
- specific for SQLAlchemy.
320
+ Class for converting columns into a supported list of filters
321
+ specific for SQLAlchemy.
256
322
 
257
323
  """
258
324
 
@@ -279,6 +345,8 @@ class SQLAFilterConverter(BaseFilterConverter):
279
345
  FilterNotEndsWith,
280
346
  FilterNotContains,
281
347
  FilterNotEqual,
348
+ FilterIn,
349
+ FilterNotIn,
282
350
  ],
283
351
  ),
284
352
  (
@@ -305,12 +373,57 @@ class SQLAFilterConverter(BaseFilterConverter):
305
373
  FilterNotEndsWith,
306
374
  FilterNotContains,
307
375
  FilterNotEqual,
376
+ FilterIn,
377
+ FilterNotIn,
378
+ ],
379
+ ),
380
+ (
381
+ "is_integer",
382
+ [
383
+ FilterEqual,
384
+ FilterGreater,
385
+ FilterSmaller,
386
+ FilterNotEqual,
387
+ FilterIn,
388
+ FilterNotIn,
389
+ ],
390
+ ),
391
+ (
392
+ "is_float",
393
+ [
394
+ FilterEqual,
395
+ FilterGreater,
396
+ FilterSmaller,
397
+ FilterNotEqual,
398
+ FilterIn,
399
+ FilterNotIn,
400
+ ],
401
+ ),
402
+ (
403
+ "is_numeric",
404
+ [
405
+ FilterEqual,
406
+ FilterGreater,
407
+ FilterSmaller,
408
+ FilterNotEqual,
409
+ FilterIn,
410
+ FilterNotIn,
308
411
  ],
309
412
  ),
310
- ("is_integer", [FilterEqual, FilterGreater, FilterSmaller, FilterNotEqual]),
311
- ("is_float", [FilterEqual, FilterGreater, FilterSmaller, FilterNotEqual]),
312
- ("is_numeric", [FilterEqual, FilterGreater, FilterSmaller, FilterNotEqual]),
313
413
  ("is_date", [FilterEqual, FilterGreater, FilterSmaller, FilterNotEqual]),
314
414
  ("is_boolean", [FilterEqual, FilterNotEqual]),
315
415
  ("is_datetime", [FilterEqual, FilterGreater, FilterSmaller, FilterNotEqual]),
416
+ (
417
+ "is_json",
418
+ [
419
+ FilterStartsWith,
420
+ FilterEndsWith,
421
+ FilterContains,
422
+ FilterEqual,
423
+ FilterNotStartsWith,
424
+ FilterNotEndsWith,
425
+ FilterNotContains,
426
+ FilterNotEqual,
427
+ ],
428
+ ),
316
429
  )