Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
flask-admin
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
JIRA
JIRA
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Python-Dev
flask-admin
Commits
6f4ef689
Commit
6f4ef689
authored
Dec 31, 2015
by
Paul Brown
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
simplify editable list view, fix list view multiple select
parent
d7df4fe4
Changes
17
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
170 additions
and
192 deletions
+170
-192
view.py
flask_admin/contrib/mongoengine/view.py
+6
-9
view.py
flask_admin/contrib/peewee/view.py
+6
-9
fields.py
flask_admin/contrib/sqla/fields.py
+3
-3
form.py
flask_admin/contrib/sqla/form.py
+0
-6
view.py
flask_admin/contrib/sqla/view.py
+6
-10
base.py
flask_admin/model/base.py
+17
-22
fields.py
flask_admin/model/fields.py
+1
-53
form.py
flask_admin/model/form.py
+18
-10
widgets.py
flask_admin/model/widgets.py
+33
-25
form.js
flask_admin/static/admin/js/form.js
+27
-2
lib.html
flask_admin/templates/bootstrap2/admin/lib.html
+1
-1
list.html
flask_admin/templates/bootstrap2/admin/model/list.html
+2
-2
lib.html
flask_admin/templates/bootstrap3/admin/lib.html
+1
-1
list.html
flask_admin/templates/bootstrap3/admin/model/list.html
+2
-2
test_basic.py
flask_admin/tests/mongoengine/test_basic.py
+13
-11
test_basic.py
flask_admin/tests/peeweemodel/test_basic.py
+17
-12
test_basic.py
flask_admin/tests/sqla/test_basic.py
+17
-14
No files found.
flask_admin/contrib/mongoengine/view.py
View file @
6f4ef689
...
@@ -5,8 +5,7 @@ from flask import request, flash, abort, Response
...
@@ -5,8 +5,7 @@ from flask import request, flash, abort, Response
from
flask_admin
import
expose
from
flask_admin
import
expose
from
flask_admin.babel
import
gettext
,
ngettext
,
lazy_gettext
from
flask_admin.babel
import
gettext
,
ngettext
,
lazy_gettext
from
flask_admin.model
import
BaseModelView
from
flask_admin.model
import
BaseModelView
from
flask_admin.model.form
import
wrap_fields_in_fieldlist
from
flask_admin.model.form
import
create_editable_list_form
from
flask_admin.model.fields
import
ListEditableFieldList
from
flask_admin._compat
import
iteritems
,
string_types
from
flask_admin._compat
import
iteritems
,
string_types
import
mongoengine
import
mongoengine
...
@@ -426,17 +425,16 @@ class ModelView(BaseModelView):
...
@@ -426,17 +425,16 @@ class ModelView(BaseModelView):
return
form_class
return
form_class
def
scaffold_list_form
(
self
,
custom_fieldlist
=
ListEditableFieldList
,
def
scaffold_list_form
(
self
,
widget
=
None
,
validators
=
None
):
validators
=
None
):
"""
"""
Create form for the `index_view` using only the columns from
Create form for the `index_view` using only the columns from
`self.column_editable_list`.
`self.column_editable_list`.
:param widget:
WTForms widget class. Defaults to `XEditableWidget`.
:param validators:
:param validators:
`form_args` dict with only validators
`form_args` dict with only validators
{'name': {'validators': [required()]}}
{'name': {'validators': [required()]}}
:param custom_fieldlist:
A WTForm FieldList class. By default, `ListEditableFieldList`.
"""
"""
form_class
=
get_form
(
self
.
model
,
form_class
=
get_form
(
self
.
model
,
self
.
model_form_converter
(
self
),
self
.
model_form_converter
(
self
),
...
@@ -444,9 +442,8 @@ class ModelView(BaseModelView):
...
@@ -444,9 +442,8 @@ class ModelView(BaseModelView):
only
=
self
.
column_editable_list
,
only
=
self
.
column_editable_list
,
field_args
=
validators
)
field_args
=
validators
)
return
wrap_fields_in_fieldlist
(
self
.
form_base_class
,
return
create_editable_list_form
(
self
.
form_base_class
,
form_class
,
form_class
,
widget
)
custom_fieldlist
)
# AJAX foreignkey support
# AJAX foreignkey support
def
_create_ajax_loader
(
self
,
name
,
opts
):
def
_create_ajax_loader
(
self
,
name
,
opts
):
...
...
flask_admin/contrib/peewee/view.py
View file @
6f4ef689
...
@@ -5,8 +5,7 @@ from flask import flash
...
@@ -5,8 +5,7 @@ from flask import flash
from
flask_admin._compat
import
string_types
,
iteritems
from
flask_admin._compat
import
string_types
,
iteritems
from
flask_admin.babel
import
gettext
,
ngettext
,
lazy_gettext
from
flask_admin.babel
import
gettext
,
ngettext
,
lazy_gettext
from
flask_admin.model
import
BaseModelView
from
flask_admin.model
import
BaseModelView
from
flask_admin.model.form
import
wrap_fields_in_fieldlist
from
flask_admin.model.form
import
create_editable_list_form
from
flask_admin.model.fields
import
ListEditableFieldList
from
peewee
import
PrimaryKeyField
,
ForeignKeyField
,
Field
,
CharField
,
TextField
from
peewee
import
PrimaryKeyField
,
ForeignKeyField
,
Field
,
CharField
,
TextField
...
@@ -265,26 +264,24 @@ class ModelView(BaseModelView):
...
@@ -265,26 +264,24 @@ class ModelView(BaseModelView):
return
form_class
return
form_class
def
scaffold_list_form
(
self
,
custom_fieldlist
=
ListEditableFieldList
,
def
scaffold_list_form
(
self
,
widget
=
None
,
validators
=
None
):
validators
=
None
):
"""
"""
Create form for the `index_view` using only the columns from
Create form for the `index_view` using only the columns from
`self.column_editable_list`.
`self.column_editable_list`.
:param widget:
WTForms widget class. Defaults to `XEditableWidget`.
:param validators:
:param validators:
`form_args` dict with only validators
`form_args` dict with only validators
{'name': {'validators': [required()]}}
{'name': {'validators': [required()]}}
:param custom_fieldlist:
A WTForm FieldList class. By default, `ListEditableFieldList`.
"""
"""
form_class
=
get_form
(
self
.
model
,
self
.
model_form_converter
(
self
),
form_class
=
get_form
(
self
.
model
,
self
.
model_form_converter
(
self
),
base_class
=
self
.
form_base_class
,
base_class
=
self
.
form_base_class
,
only
=
self
.
column_editable_list
,
only
=
self
.
column_editable_list
,
field_args
=
validators
)
field_args
=
validators
)
return
wrap_fields_in_fieldlist
(
self
.
form_base_class
,
return
create_editable_list_form
(
self
.
form_base_class
,
form_class
,
form_class
,
widget
)
custom_fieldlist
)
def
scaffold_inline_form_models
(
self
,
form_class
):
def
scaffold_inline_form_models
(
self
,
form_class
):
converter
=
self
.
model_form_converter
(
self
)
converter
=
self
.
model_form_converter
(
self
)
...
...
flask_admin/contrib/sqla/fields.py
View file @
6f4ef689
...
@@ -14,7 +14,7 @@ except ImportError:
...
@@ -14,7 +14,7 @@ except ImportError:
from
.tools
import
get_primary_key
from
.tools
import
get_primary_key
from
flask_admin._compat
import
text_type
,
string_types
,
iteritems
from
flask_admin._compat
import
text_type
,
string_types
,
iteritems
from
flask_admin.form
import
FormOpts
,
BaseForm
from
flask_admin.form
import
FormOpts
,
BaseForm
,
Select2Widget
from
flask_admin.model.fields
import
InlineFieldList
,
InlineModelFormField
from
flask_admin.model.fields
import
InlineFieldList
,
InlineModelFormField
from
flask_admin.babel
import
lazy_gettext
from
flask_admin.babel
import
lazy_gettext
...
@@ -55,7 +55,7 @@ class QuerySelectField(SelectFieldBase):
...
@@ -55,7 +55,7 @@ class QuerySelectField(SelectFieldBase):
being `None`. The label for this blank choice can be set by specifying the
being `None`. The label for this blank choice can be set by specifying the
`blank_text` parameter.
`blank_text` parameter.
"""
"""
widget
=
widgets
.
Selec
t
()
widget
=
Select2Widge
t
()
def
__init__
(
self
,
label
=
None
,
validators
=
None
,
query_factory
=
None
,
def
__init__
(
self
,
label
=
None
,
validators
=
None
,
query_factory
=
None
,
get_pk
=
None
,
get_label
=
None
,
allow_blank
=
False
,
get_pk
=
None
,
get_label
=
None
,
allow_blank
=
False
,
...
@@ -136,7 +136,7 @@ class QuerySelectMultipleField(QuerySelectField):
...
@@ -136,7 +136,7 @@ class QuerySelectMultipleField(QuerySelectField):
If any of the items in the data list or submitted form data cannot be
If any of the items in the data list or submitted form data cannot be
found in the query, this will result in a validation error.
found in the query, this will result in a validation error.
"""
"""
widget
=
widgets
.
Selec
t
(
multiple
=
True
)
widget
=
Select2Widge
t
(
multiple
=
True
)
def
__init__
(
self
,
label
=
None
,
validators
=
None
,
default
=
None
,
**
kwargs
):
def
__init__
(
self
,
label
=
None
,
validators
=
None
,
default
=
None
,
**
kwargs
):
if
default
is
None
:
if
default
is
None
:
...
...
flask_admin/contrib/sqla/form.py
View file @
6f4ef689
...
@@ -80,12 +80,6 @@ class AdminModelConverter(ModelConverterBase):
...
@@ -80,12 +80,6 @@ class AdminModelConverter(ModelConverterBase):
if
'query_factory'
not
in
kwargs
:
if
'query_factory'
not
in
kwargs
:
kwargs
[
'query_factory'
]
=
lambda
:
self
.
session
.
query
(
remote_model
)
kwargs
[
'query_factory'
]
=
lambda
:
self
.
session
.
query
(
remote_model
)
if
'widget'
not
in
kwargs
:
if
multiple
:
kwargs
[
'widget'
]
=
form
.
Select2Widget
(
multiple
=
True
)
else
:
kwargs
[
'widget'
]
=
form
.
Select2Widget
()
if
multiple
:
if
multiple
:
return
QuerySelectMultipleField
(
**
kwargs
)
return
QuerySelectMultipleField
(
**
kwargs
)
else
:
else
:
...
...
flask_admin/contrib/sqla/view.py
View file @
6f4ef689
...
@@ -15,9 +15,7 @@ from flask import flash
...
@@ -15,9 +15,7 @@ from flask import flash
from
flask_admin._compat
import
string_types
,
text_type
from
flask_admin._compat
import
string_types
,
text_type
from
flask_admin.babel
import
gettext
,
ngettext
,
lazy_gettext
from
flask_admin.babel
import
gettext
,
ngettext
,
lazy_gettext
from
flask_admin.model
import
BaseModelView
from
flask_admin.model
import
BaseModelView
from
flask_admin.model.form
import
wrap_fields_in_fieldlist
from
flask_admin.model.form
import
create_editable_list_form
from
flask_admin.model.fields
import
ListEditableFieldList
from
flask_admin.actions
import
action
from
flask_admin.actions
import
action
from
flask_admin._backwards
import
ObsoleteAttr
from
flask_admin._backwards
import
ObsoleteAttr
...
@@ -675,17 +673,16 @@ class ModelView(BaseModelView):
...
@@ -675,17 +673,16 @@ class ModelView(BaseModelView):
return
form_class
return
form_class
def
scaffold_list_form
(
self
,
custom_fieldlist
=
ListEditableFieldList
,
def
scaffold_list_form
(
self
,
widget
=
None
,
validators
=
None
):
validators
=
None
):
"""
"""
Create form for the `index_view` using only the columns from
Create form for the `index_view` using only the columns from
`self.column_editable_list`.
`self.column_editable_list`.
:param widget:
WTForms widget class. Defaults to `XEditableWidget`.
:param validators:
:param validators:
`form_args` dict with only validators
`form_args` dict with only validators
{'name': {'validators': [required()]}}
{'name': {'validators': [required()]}}
:param custom_fieldlist:
A WTForm FieldList class. By default, `ListEditableFieldList`.
"""
"""
converter
=
self
.
model_form_converter
(
self
.
session
,
self
)
converter
=
self
.
model_form_converter
(
self
.
session
,
self
)
form_class
=
form
.
get_form
(
self
.
model
,
converter
,
form_class
=
form
.
get_form
(
self
.
model
,
converter
,
...
@@ -693,9 +690,8 @@ class ModelView(BaseModelView):
...
@@ -693,9 +690,8 @@ class ModelView(BaseModelView):
only
=
self
.
column_editable_list
,
only
=
self
.
column_editable_list
,
field_args
=
validators
)
field_args
=
validators
)
return
wrap_fields_in_fieldlist
(
self
.
form_base_class
,
return
create_editable_list_form
(
self
.
form_base_class
,
form_class
,
form_class
,
widget
)
custom_fieldlist
)
def
scaffold_inline_form_models
(
self
,
form_class
):
def
scaffold_inline_form_models
(
self
,
form_class
):
"""
"""
...
...
flask_admin/model/base.py
View file @
6f4ef689
...
@@ -26,7 +26,6 @@ from flask_admin._compat import (iteritems, itervalues, OrderedDict,
...
@@ -26,7 +26,6 @@ from flask_admin._compat import (iteritems, itervalues, OrderedDict,
as_unicode
,
csv_encode
,
text_type
)
as_unicode
,
csv_encode
,
text_type
)
from
.helpers
import
prettify_name
,
get_mdict_item_or_list
from
.helpers
import
prettify_name
,
get_mdict_item_or_list
from
.ajax
import
AjaxModelLoader
from
.ajax
import
AjaxModelLoader
from
.fields
import
ListEditableFieldList
# Used to generate filter query string name
# Used to generate filter query string name
filter_char_re
=
re
.
compile
(
'[^a-z0-9 ]'
)
filter_char_re
=
re
.
compile
(
'[^a-z0-9 ]'
)
...
@@ -1069,17 +1068,16 @@ class BaseModelView(BaseView, ActionsMixin):
...
@@ -1069,17 +1068,16 @@ class BaseModelView(BaseView, ActionsMixin):
"""
"""
raise
NotImplementedError
(
'Please implement scaffold_form method'
)
raise
NotImplementedError
(
'Please implement scaffold_form method'
)
def
scaffold_list_form
(
self
,
custom_fieldlist
=
ListEditableFieldList
,
def
scaffold_list_form
(
self
,
widget
=
None
,
validators
=
None
):
validators
=
None
):
"""
"""
Create form for the `index_view` using only the columns from
Create form for the `index_view` using only the columns from
`self.column_editable_list`.
`self.column_editable_list`.
:param widget:
WTForms widget class. Defaults to `XEditableWidget`.
:param validators:
:param validators:
`form_args` dict with only validators
`form_args` dict with only validators
{'name': {'validators': [DataRequired()]}}
{'name': {'validators': [DataRequired()]}}
:param custom_fieldlist:
A WTForm FieldList class. By default, `ListEditableFieldList`.
Must be implemented in the child class.
Must be implemented in the child class.
"""
"""
...
@@ -1107,7 +1105,6 @@ class BaseModelView(BaseView, ActionsMixin):
...
@@ -1107,7 +1105,6 @@ class BaseModelView(BaseView, ActionsMixin):
Allows overriding the editable list view field/widget. For example::
Allows overriding the editable list view field/widget. For example::
from flask_admin.model.fields import ListEditableFieldList
from flask_admin.model.widgets import XEditableWidget
from flask_admin.model.widgets import XEditableWidget
class CustomWidget(XEditableWidget):
class CustomWidget(XEditableWidget):
...
@@ -1119,12 +1116,9 @@ class BaseModelView(BaseView, ActionsMixin):
...
@@ -1119,12 +1116,9 @@ class BaseModelView(BaseView, ActionsMixin):
return kwargs
return kwargs
class CustomFieldList(ListEditableFieldList):
widget = CustomWidget()
class MyModelView(BaseModelView):
class MyModelView(BaseModelView):
def get_list_form(self):
def get_list_form(self):
return self.scaffold_list_form(
CustomFieldLis
t)
return self.scaffold_list_form(
widget=CustomWidge
t)
"""
"""
if
self
.
form_args
:
if
self
.
form_args
:
# get only validators, other form_args can break FieldList wrapper
# get only validators, other form_args can break FieldList wrapper
...
@@ -1716,7 +1710,7 @@ class BaseModelView(BaseView, ActionsMixin):
...
@@ -1716,7 +1710,7 @@ class BaseModelView(BaseView, ActionsMixin):
List view
List view
"""
"""
if
self
.
column_editable_list
:
if
self
.
column_editable_list
:
form
=
self
.
list_form
()
form
=
self
.
list_form
else
:
else
:
form
=
None
form
=
None
...
@@ -2074,24 +2068,23 @@ class BaseModelView(BaseView, ActionsMixin):
...
@@ -2074,24 +2068,23 @@ class BaseModelView(BaseView, ActionsMixin):
if
not
self
.
column_editable_list
:
if
not
self
.
column_editable_list
:
abort
(
404
)
abort
(
404
)
record
=
None
form
=
self
.
list_form
()
form
=
self
.
list_form
()
# prevent validation issues due to submitting a single field
# prevent validation issues due to submitting a single field
# delete all fields except the
field being submitted
# delete all fields except the
submitted fields and csrf token
for
field
in
form
:
for
field
in
form
:
# only the submitted field has a positive last_index
if
(
field
.
name
in
request
.
form
)
or
(
field
.
name
==
'csrf_token'
):
if
getattr
(
field
,
'last_index'
,
0
):
record
=
self
.
get_one
(
str
(
field
.
last_index
))
elif
field
.
name
==
'csrf_token'
:
pass
pass
else
:
else
:
form
.
__delitem__
(
field
.
name
)
form
.
__delitem__
(
field
.
name
)
if
record
is
None
:
return
gettext
(
'Failed to update record.
%(error)
s'
,
error
=
''
),
500
if
self
.
validate_form
(
form
):
if
self
.
validate_form
(
form
):
pk
=
form
.
list_form_pk
.
data
record
=
self
.
get_one
(
pk
)
if
record
is
None
:
return
gettext
(
'Record does not exist.'
),
500
if
self
.
update_model
(
form
,
record
):
if
self
.
update_model
(
form
,
record
):
# Success
# Success
return
gettext
(
'Record was successfully saved.'
)
return
gettext
(
'Record was successfully saved.'
)
...
@@ -2105,6 +2098,8 @@ class BaseModelView(BaseView, ActionsMixin):
...
@@ -2105,6 +2098,8 @@ class BaseModelView(BaseView, ActionsMixin):
for
error
in
field
.
errors
:
for
error
in
field
.
errors
:
# return validation error to x-editable
# return validation error to x-editable
if
isinstance
(
error
,
list
):
if
isinstance
(
error
,
list
):
return
", "
.
join
(
error
),
500
return
gettext
(
'Failed to update record.
%(error)
s'
,
error
=
", "
.
join
(
error
)),
500
else
:
else
:
return
error
,
500
return
gettext
(
'Failed to update record.
%(error)
s'
,
error
=
error
),
500
flask_admin/model/fields.py
View file @
6f4ef689
...
@@ -10,7 +10,7 @@ except ImportError:
...
@@ -10,7 +10,7 @@ except ImportError:
from
flask_admin._compat
import
iteritems
from
flask_admin._compat
import
iteritems
from
.widgets
import
(
InlineFieldListWidget
,
InlineFormWidget
,
from
.widgets
import
(
InlineFieldListWidget
,
InlineFormWidget
,
AjaxSelect2Widget
,
XEditableWidget
)
AjaxSelect2Widget
)
class
InlineFieldList
(
FieldList
):
class
InlineFieldList
(
FieldList
):
...
@@ -126,58 +126,6 @@ class InlineModelFormField(FormField):
...
@@ -126,58 +126,6 @@ class InlineModelFormField(FormField):
field
.
populate_obj
(
obj
,
name
)
field
.
populate_obj
(
obj
,
name
)
class
ListEditableFieldList
(
FieldList
):
"""
Modified FieldList to allow for alphanumeric primary keys.
Used in the editable list view.
"""
widget
=
XEditableWidget
()
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
ListEditableFieldList
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
# min_entries = 1 is required for the widget to determine the type
self
.
min_entries
=
1
def
_extract_indices
(
self
,
prefix
,
formdata
):
offset
=
len
(
prefix
)
+
1
for
name
in
formdata
:
# selects only relevant field (not CSRF, other fields, etc)
if
name
.
startswith
(
prefix
):
# exclude offset (prefix-), remaining text is the index
yield
name
[
offset
:]
def
_add_entry
(
self
,
formdata
=
None
,
data
=
unset_value
,
index
=
None
):
assert
not
self
.
max_entries
or
len
(
self
.
entries
)
<
self
.
max_entries
,
\
'You cannot have more than max_entries entries in this FieldList'
if
index
is
None
:
index
=
self
.
last_index
+
1
self
.
last_index
=
index
# '%s-%s' instead of '%s-%d' to allow alphanumeric
name
=
'
%
s-
%
s'
%
(
self
.
short_name
,
index
)
id
=
'
%
s-
%
s'
%
(
self
.
id
,
index
)
# support both wtforms 1 and 2
meta
=
getattr
(
self
,
'meta'
,
None
)
if
meta
:
field
=
self
.
unbound_field
.
bind
(
form
=
None
,
name
=
name
,
prefix
=
self
.
_prefix
,
id
=
id
,
_meta
=
meta
)
else
:
field
=
self
.
unbound_field
.
bind
(
form
=
None
,
name
=
name
,
prefix
=
self
.
_prefix
,
id
=
id
)
field
.
process
(
formdata
,
data
)
self
.
entries
.
append
(
field
)
return
field
def
populate_obj
(
self
,
obj
,
name
):
# return data from first item, instead of a list of items
setattr
(
obj
,
name
,
self
.
data
.
pop
())
class
AjaxSelectField
(
SelectFieldBase
):
class
AjaxSelectField
(
SelectFieldBase
):
"""
"""
Ajax Model Select Field
Ajax Model Select Field
...
...
flask_admin/model/form.py
View file @
6f4ef689
...
@@ -3,7 +3,10 @@ import inspect
...
@@ -3,7 +3,10 @@ import inspect
from
flask_admin.form
import
BaseForm
,
rules
from
flask_admin.form
import
BaseForm
,
rules
from
flask_admin._compat
import
iteritems
from
flask_admin._compat
import
iteritems
from
wtforms.fields
import
HiddenField
from
wtforms.fields.core
import
UnboundField
from
wtforms.fields.core
import
UnboundField
from
wtforms.validators
import
InputRequired
from
.widgets
import
XEditableWidget
def
converts
(
*
args
):
def
converts
(
*
args
):
...
@@ -13,7 +16,7 @@ def converts(*args):
...
@@ -13,7 +16,7 @@ def converts(*args):
return
_inner
return
_inner
def
wrap_fields_in_fieldlist
(
form_base_class
,
form_class
,
CustomFieldList
):
def
create_editable_list_form
(
form_base_class
,
form_class
,
widget
=
None
):
"""
"""
Create a form class with all the fields wrapped in a FieldList.
Create a form class with all the fields wrapped in a FieldList.
...
@@ -26,20 +29,25 @@ def wrap_fields_in_fieldlist(form_base_class, form_class, CustomFieldList):
...
@@ -26,20 +29,25 @@ def wrap_fields_in_fieldlist(form_base_class, form_class, CustomFieldList):
WTForms form class, by default `form_base_class` from base.
WTForms form class, by default `form_base_class` from base.
:param form_class:
:param form_class:
WTForms form class generated by `form.get_form`.
WTForms form class generated by `form.get_form`.
:param CustomFieldList:
:param widget:
WTForms FieldList class.
WTForms widget class. Defaults to `XEditableWidget`.
By default, `CustomFieldList` is `ListEditableFieldList`.
"""
"""
class
FieldListForm
(
form_base_class
):
if
widget
is
None
:
pass
widget
=
XEditableWidget
class
ListForm
(
form_base_class
):
list_form_pk
=
HiddenField
(
validators
=
[
InputRequired
()])
# iterate FormMeta to get unbound fields
# iterate FormMeta to get unbound fields
, replace widget, copy to ListForm
for
name
,
obj
in
iteritems
(
form_class
.
__dict__
):
for
name
,
obj
in
iteritems
(
form_class
.
__dict__
):
if
isinstance
(
obj
,
UnboundField
):
if
isinstance
(
obj
,
UnboundField
):
# wrap field in a WTForms FieldList
obj
.
kwargs
[
'widget'
]
=
XEditableWidget
()
setattr
(
FieldListForm
,
name
,
CustomFieldList
(
obj
))
setattr
(
ListForm
,
name
,
obj
)
if
name
==
"list_form_pk"
:
raise
Exception
(
'Form already has a list_form_pk column.'
)
return
Field
ListForm
return
ListForm
class
InlineBaseFormAdmin
(
object
):
class
InlineBaseFormAdmin
(
object
):
...
...
flask_admin/model/widgets.py
View file @
6f4ef689
...
@@ -72,7 +72,7 @@ class XEditableWidget(object):
...
@@ -72,7 +72,7 @@ class XEditableWidget(object):
field inside of the FieldList (StringField, IntegerField, etc).
field inside of the FieldList (StringField, IntegerField, etc).
"""
"""
def
__call__
(
self
,
field
,
**
kwargs
):
def
__call__
(
self
,
field
,
**
kwargs
):
kwargs
.
setdefault
(
'data-value'
,
kwargs
.
pop
(
'value'
,
''
))
kwargs
.
setdefault
(
'data-value'
,
kwargs
.
pop
(
'
display_
value'
,
''
))
kwargs
.
setdefault
(
'data-role'
,
'x-editable'
)
kwargs
.
setdefault
(
'data-role'
,
'x-editable'
)
kwargs
.
setdefault
(
'data-url'
,
'./ajax/update/'
)
kwargs
.
setdefault
(
'data-url'
,
'./ajax/update/'
)
...
@@ -87,26 +87,23 @@ class XEditableWidget(object):
...
@@ -87,26 +87,23 @@ class XEditableWidget(object):
kwargs
[
'data-csrf'
]
=
kwargs
.
pop
(
"csrf"
,
""
)
kwargs
[
'data-csrf'
]
=
kwargs
.
pop
(
"csrf"
,
""
)
# subfield is the first entry (subfield) from FieldList (field)
kwargs
=
self
.
get_kwargs
(
field
,
kwargs
)
subfield
=
field
.
entries
[
0
]
kwargs
=
self
.
get_kwargs
(
subfield
,
kwargs
)
return
HTMLString
(
return
HTMLString
(
'<a
%
s>
%
s</a>'
%
(
html_params
(
**
kwargs
),
'<a
%
s>
%
s</a>'
%
(
html_params
(
**
kwargs
),
escape
(
kwargs
[
'data-value'
]))
escape
(
kwargs
[
'data-value'
]))
)
)
def
get_kwargs
(
self
,
sub
field
,
kwargs
):
def
get_kwargs
(
self
,
field
,
kwargs
):
"""
"""
Return extra kwargs based on the
sub
field type.
Return extra kwargs based on the field type.
"""
"""
if
sub
field
.
type
==
'StringField'
:
if
field
.
type
==
'StringField'
:
kwargs
[
'data-type'
]
=
'text'
kwargs
[
'data-type'
]
=
'text'
elif
sub
field
.
type
==
'TextAreaField'
:
elif
field
.
type
==
'TextAreaField'
:
kwargs
[
'data-type'
]
=
'textarea'
kwargs
[
'data-type'
]
=
'textarea'
kwargs
[
'data-rows'
]
=
'5'
kwargs
[
'data-rows'
]
=
'5'
elif
sub
field
.
type
==
'BooleanField'
:
elif
field
.
type
==
'BooleanField'
:
kwargs
[
'data-type'
]
=
'select'
kwargs
[
'data-type'
]
=
'select'
# data-source = dropdown options
# data-source = dropdown options
kwargs
[
'data-source'
]
=
json
.
dumps
([
kwargs
[
'data-source'
]
=
json
.
dumps
([
...
@@ -114,53 +111,64 @@ class XEditableWidget(object):
...
@@ -114,53 +111,64 @@ class XEditableWidget(object):
{
'value'
:
'1'
,
'text'
:
gettext
(
'Yes'
)}
{
'value'
:
'1'
,
'text'
:
gettext
(
'Yes'
)}
])
])
kwargs
[
'data-role'
]
=
'x-editable-boolean'
kwargs
[
'data-role'
]
=
'x-editable-boolean'
elif
sub
field
.
type
==
'Select2Field'
:
elif
field
.
type
==
'Select2Field'
:
kwargs
[
'data-type'
]
=
'select'
kwargs
[
'data-type'
]
=
'select'
choices
=
[{
'value'
:
x
,
'text'
:
y
}
for
x
,
y
in
sub
field
.
choices
]
choices
=
[{
'value'
:
x
,
'text'
:
y
}
for
x
,
y
in
field
.
choices
]
# prepend a blank field to choices if allow_blank = True
# prepend a blank field to choices if allow_blank = True
if
getattr
(
sub
field
,
'allow_blank'
,
False
):
if
getattr
(
field
,
'allow_blank'
,
False
):
choices
.
insert
(
0
,
{
'value'
:
'__None'
,
'text'
:
''
})
choices
.
insert
(
0
,
{
'value'
:
'__None'
,
'text'
:
''
})
# json.dumps fixes issue with unicode strings not loading correctly
# json.dumps fixes issue with unicode strings not loading correctly
kwargs
[
'data-source'
]
=
json
.
dumps
(
choices
)
kwargs
[
'data-source'
]
=
json
.
dumps
(
choices
)
elif
sub
field
.
type
==
'DateField'
:
elif
field
.
type
==
'DateField'
:
kwargs
[
'data-type'
]
=
'combodate'
kwargs
[
'data-type'
]
=
'combodate'
kwargs
[
'data-format'
]
=
'YYYY-MM-DD'
kwargs
[
'data-format'
]
=
'YYYY-MM-DD'
kwargs
[
'data-template'
]
=
'YYYY-MM-DD'
kwargs
[
'data-template'
]
=
'YYYY-MM-DD'
elif
sub
field
.
type
==
'DateTimeField'
:
elif
field
.
type
==
'DateTimeField'
:
kwargs
[
'data-type'
]
=
'combodate'
kwargs
[
'data-type'
]
=
'combodate'
kwargs
[
'data-format'
]
=
'YYYY-MM-DD HH:mm:ss'
kwargs
[
'data-format'
]
=
'YYYY-MM-DD HH:mm:ss'
kwargs
[
'data-template'
]
=
'YYYY-MM-DD HH:mm:ss'
kwargs
[
'data-template'
]
=
'YYYY-MM-DD HH:mm:ss'
# x-editable-combodate uses 1 minute increments
# x-editable-combodate uses 1 minute increments
kwargs
[
'data-role'
]
=
'x-editable-combodate'
kwargs
[
'data-role'
]
=
'x-editable-combodate'
elif
sub
field
.
type
==
'TimeField'
:
elif
field
.
type
==
'TimeField'
:
kwargs
[
'data-type'
]
=
'combodate'
kwargs
[
'data-type'
]
=
'combodate'
kwargs
[
'data-format'
]
=
'HH:mm:ss'
kwargs
[
'data-format'
]
=
'HH:mm:ss'
kwargs
[
'data-template'
]
=
'HH:mm:ss'
kwargs
[
'data-template'
]
=
'HH:mm:ss'
kwargs
[
'data-role'
]
=
'x-editable-combodate'
kwargs
[
'data-role'
]
=
'x-editable-combodate'
elif
sub
field
.
type
==
'IntegerField'
:
elif
field
.
type
==
'IntegerField'
:
kwargs
[
'data-type'
]
=
'number'
kwargs
[
'data-type'
]
=
'number'
elif
sub
field
.
type
in
[
'FloatField'
,
'DecimalField'
]:
elif
field
.
type
in
[
'FloatField'
,
'DecimalField'
]:
kwargs
[
'data-type'
]
=
'number'
kwargs
[
'data-type'
]
=
'number'
kwargs
[
'data-step'
]
=
'any'
kwargs
[
'data-step'
]
=
'any'
elif
subfield
.
type
in
[
'QuerySelectField'
,
'ModelSelectField'
]:
elif
field
.
type
in
[
'QuerySelectField'
,
'ModelSelectField'
,
'QuerySelectMultipleField'
]:
# QuerySelectField and ModelSelectField are for relations
# QuerySelectField and ModelSelectField are for relations
kwargs
[
'data-type'
]
=
'select'
kwargs
[
'data-type'
]
=
'select'
choices
=
[]
choices
=
[]
for
choice
in
subfield
:
selected_ids
=
[]
for
value
,
label
,
selected
in
field
.
iter_choices
():
try
:
try
:
choices
.
append
({
'value'
:
text_type
(
choice
.
_value
()),
label
=
text_type
(
label
)
'text'
:
text_type
(
choice
.
label
.
text
)})
except
TypeError
:
except
TypeError
:
# unable to display text value
# unable to display text value
choices
.
append
({
'value'
:
text_type
(
choice
.
_value
()),
label
=
''
'text'
:
''
})
choices
.
append
({
'value'
:
text_type
(
value
),
'text'
:
label
})
if
selected
:
selected_ids
.
append
(
value
)
# blank field is already included if allow_blank
# blank field is already included if allow_blank
kwargs
[
'data-source'
]
=
json
.
dumps
(
choices
)
kwargs
[
'data-source'
]
=
json
.
dumps
(
choices
)
if
field
.
type
==
'QuerySelectMultipleField'
:
kwargs
[
'data-type'
]
=
'select2'
kwargs
[
'data-role'
]
=
'x-editable-select2-multiple'
# must use id instead of text or prefilled values won't work
separator
=
getattr
(
field
,
'separator'
,
','
)
kwargs
[
'data-value'
]
=
separator
.
join
(
selected_ids
)
else
:
else
:
raise
Exception
(
'Unsupported field type:
%
s'
%
(
type
(
sub
field
),))
raise
Exception
(
'Unsupported field type:
%
s'
%
(
type
(
field
),))
return
kwargs
return
kwargs
flask_admin/static/admin/js/form.js
View file @
6f4ef689
...
@@ -272,11 +272,12 @@
...
@@ -272,11 +272,12 @@
return
true
;
return
true
;
}
}
// make x-editable's POST
act like a normal FieldList field
// make x-editable's POST
compatible with WTForms
// for x-editable, x-editable-combodate, and x-editable-boolean cases
// for x-editable, x-editable-combodate, and x-editable-boolean cases
var
overrideXeditableParams
=
function
(
params
)
{
var
overrideXeditableParams
=
function
(
params
)
{
var
newParams
=
{};
var
newParams
=
{};
newParams
[
params
.
name
+
'-'
+
params
.
pk
]
=
params
.
value
;
newParams
[
'list_form_pk'
]
=
params
.
pk
;
newParams
[
params
.
name
]
=
params
.
value
;
if
(
$
(
this
).
data
(
'csrf'
))
{
if
(
$
(
this
).
data
(
'csrf'
))
{
newParams
[
'csrf_token'
]
=
$
(
this
).
data
(
'csrf'
);
newParams
[
'csrf_token'
]
=
$
(
this
).
data
(
'csrf'
);
}
}
...
@@ -451,6 +452,30 @@
...
@@ -451,6 +452,30 @@
}
}
});
});
return
true
;
return
true
;
case
'x-editable-select2-multiple'
:
$el
.
editable
({
params
:
overrideXeditableParams
,
ajaxOptions
:
{
// prevents keys with the same value from getting converted into arrays
traditional
:
true
},
select2
:
{
multiple
:
true
},
display
:
function
(
value
)
{
// override to display text instead of ids on list view
var
html
=
[];
var
data
=
$
.
fn
.
editableutils
.
itemsByValue
(
value
,
$el
.
data
(
'source'
),
'id'
);
if
(
data
.
length
)
{
$
.
each
(
data
,
function
(
i
,
v
)
{
html
.
push
(
$
.
fn
.
editableutils
.
escape
(
v
.
text
));
});
$
(
this
).
html
(
html
.
join
(
', '
));
}
else
{
$
(
this
).
empty
();
}
}
});
return
true
;
case
'x-editable-boolean'
:
case
'x-editable-boolean'
:
$el
.
editable
({
$el
.
editable
({
params
:
overrideXeditableParams
,
params
:
overrideXeditableParams
,
...
...
flask_admin/templates/bootstrap2/admin/lib.html
View file @
6f4ef689
...
@@ -249,5 +249,5 @@
...
@@ -249,5 +249,5 @@
{% if editable_columns %}
{% if editable_columns %}
<script
src=
"{{ admin_static.url(filename='vendor/x-editable/js/bootstrap2-editable.min.js', v='1.5.1') }}"
></script>
<script
src=
"{{ admin_static.url(filename='vendor/x-editable/js/bootstrap2-editable.min.js', v='1.5.1') }}"
></script>
{% endif %}
{% endif %}
<script
src=
"{{ admin_static.url(filename='admin/js/form.js', v='1.0.
0
') }}"
></script>
<script
src=
"{{ admin_static.url(filename='admin/js/form.js', v='1.0.
1
') }}"
></script>
{% endmacro %}
{% endmacro %}
flask_admin/templates/bootstrap2/admin/model/list.html
View file @
6f4ef689
...
@@ -158,9 +158,9 @@
...
@@ -158,9 +158,9 @@
<td
class=
"col-{{c}}"
>
<td
class=
"col-{{c}}"
>
{% if admin_view.is_editable(c) %}
{% if admin_view.is_editable(c) %}
{% if form.csrf_token %}
{% if form.csrf_token %}
{{ form
[c](pk=get_pk_value(row),
value=get_value(row, c), csrf=form.csrf_token._value()) }}
{{ form
(obj=row)[c](pk=get_pk_value(row), display_
value=get_value(row, c), csrf=form.csrf_token._value()) }}
{% else %}
{% else %}
{{ form
[c](pk=get_pk_value(row),
value=get_value(row, c)) }}
{{ form
(obj=row)[c](pk=get_pk_value(row), display_
value=get_value(row, c)) }}
{% endif %}
{% endif %}
{% else %}
{% else %}
{{ get_value(row, c) }}
{{ get_value(row, c) }}
...
...
flask_admin/templates/bootstrap3/admin/lib.html
View file @
6f4ef689
...
@@ -233,5 +233,5 @@
...
@@ -233,5 +233,5 @@
{% if editable_columns %}
{% if editable_columns %}
<script
src=
"{{ admin_static.url(filename='vendor/x-editable/js/bootstrap3-editable.min.js', v='1.5.1') }}"
></script>
<script
src=
"{{ admin_static.url(filename='vendor/x-editable/js/bootstrap3-editable.min.js', v='1.5.1') }}"
></script>
{% endif %}
{% endif %}
<script
src=
"{{ admin_static.url(filename='admin/js/form.js', v='1.0.
0
') }}"
></script>
<script
src=
"{{ admin_static.url(filename='admin/js/form.js', v='1.0.
1
') }}"
></script>
{% endmacro %}
{% endmacro %}
flask_admin/templates/bootstrap3/admin/model/list.html
View file @
6f4ef689
...
@@ -157,9 +157,9 @@
...
@@ -157,9 +157,9 @@
<td
class=
"col-{{c}}"
>
<td
class=
"col-{{c}}"
>
{% if admin_view.is_editable(c) %}
{% if admin_view.is_editable(c) %}
{% if form.csrf_token %}
{% if form.csrf_token %}
{{ form
[c](pk=get_pk_value(row),
value=get_value(row, c), csrf=form.csrf_token._value()) }}
{{ form
(obj=row)[c](pk=get_pk_value(row), display_
value=get_value(row, c), csrf=form.csrf_token._value()) }}
{% else %}
{% else %}
{{ form
[c](pk=get_pk_value(row),
value=get_value(row, c)) }}
{{ form
(obj=row)[c](pk=get_pk_value(row), display_
value=get_value(row, c)) }}
{% endif %}
{% endif %}
{% else %}
{% else %}
{{ get_value(row, c) }}
{{ get_value(row, c) }}
...
...
flask_admin/tests/mongoengine/test_basic.py
View file @
6f4ef689
...
@@ -148,8 +148,7 @@ def test_column_editable_list():
...
@@ -148,8 +148,7 @@ def test_column_editable_list():
Model1
,
Model2
=
create_models
(
db
)
Model1
,
Model2
=
create_models
(
db
)
view
=
CustomModelView
(
Model1
,
view
=
CustomModelView
(
Model1
,
column_editable_list
=
[
column_editable_list
=
[
'test1'
,
'datetime_field'
])
'test1'
,
'datetime_field'
])
admin
.
add_view
(
view
)
admin
.
add_view
(
view
)
fill_db
(
Model1
,
Model2
)
fill_db
(
Model1
,
Model2
)
...
@@ -164,7 +163,8 @@ def test_column_editable_list():
...
@@ -164,7 +163,8 @@ def test_column_editable_list():
# Form - Test basic in-line edit functionality
# Form - Test basic in-line edit functionality
obj1
=
Model1
.
objects
.
get
(
test1
=
'test1_val_3'
)
obj1
=
Model1
.
objects
.
get
(
test1
=
'test1_val_3'
)
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
'test1-'
+
str
(
obj1
.
id
):
'change-success-1'
,
'list_form_pk'
:
str
(
obj1
.
id
),
'test1'
:
'change-success-1'
,
})
})
data
=
rv
.
data
.
decode
(
'utf-8'
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'Record was successfully saved.'
==
data
)
ok_
(
'Record was successfully saved.'
==
data
)
...
@@ -177,33 +177,35 @@ def test_column_editable_list():
...
@@ -177,33 +177,35 @@ def test_column_editable_list():
# Test validation error
# Test validation error
obj2
=
Model1
.
objects
.
get
(
test1
=
'datetime_obj1'
)
obj2
=
Model1
.
objects
.
get
(
test1
=
'datetime_obj1'
)
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
'datetime_field-'
+
str
(
obj2
.
id
):
'problematic-input'
,
'list_form_pk'
:
str
(
obj2
.
id
),
'datetime_field'
:
'problematic-input'
,
})
})
eq_
(
rv
.
status_code
,
500
)
eq_
(
rv
.
status_code
,
500
)
# Test invalid primary key
# Test invalid primary key
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
'test1-1000'
:
'problematic-input'
,
'list_form_pk'
:
'1000'
,
'test1'
:
'problematic-input'
,
})
})
data
=
rv
.
data
.
decode
(
'utf-8'
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
eq_
(
rv
.
status_code
,
500
)
eq_
(
rv
.
status_code
,
500
)
# Test editing column not in column_editable_list
# Test editing column not in column_editable_list
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
'test2-1'
:
'problematic-input'
,
'list_form_pk'
:
'1'
,
'test2'
:
'problematic-input'
,
})
})
data
=
rv
.
data
.
decode
(
'utf-8'
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
eq_
(
rv
.
status_code
,
500
)
ok_
(
'problematic-input'
not
in
data
)
# Test in-line editing for relations
# Test in-line editing for relations
view
=
CustomModelView
(
Model2
,
view
=
CustomModelView
(
Model2
,
column_editable_list
=
[
'model1'
])
column_editable_list
=
[
'model1'
])
admin
.
add_view
(
view
)
admin
.
add_view
(
view
)
obj3
=
Model2
.
objects
.
get
(
string_field
=
'string_field_val_1'
)
obj3
=
Model2
.
objects
.
get
(
string_field
=
'string_field_val_1'
)
rv
=
client
.
post
(
'/admin/model2/ajax/update/'
,
data
=
{
rv
=
client
.
post
(
'/admin/model2/ajax/update/'
,
data
=
{
'model1-'
+
str
(
obj3
.
id
):
str
(
obj1
.
id
),
'list_form_pk'
:
str
(
obj3
.
id
),
'model1'
:
str
(
obj1
.
id
),
})
})
data
=
rv
.
data
.
decode
(
'utf-8'
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'Record was successfully saved.'
==
data
)
ok_
(
'Record was successfully saved.'
==
data
)
...
...
flask_admin/tests/peeweemodel/test_basic.py
View file @
6f4ef689
...
@@ -185,9 +185,10 @@ def test_column_editable_list():
...
@@ -185,9 +185,10 @@ def test_column_editable_list():
Model1
,
Model2
=
create_models
(
db
)
Model1
,
Model2
=
create_models
(
db
)
view
=
CustomModelView
(
Model1
,
# wtf-peewee doesn't automatically add length validators for max_length
column_editable_list
=
[
form_args
=
{
'test1'
:
{
'validators'
:
[
validators
.
Length
(
max
=
20
)]}}
'test1'
,
'enum_field'
])
view
=
CustomModelView
(
Model1
,
column_editable_list
=
[
'test1'
],
form_args
=
form_args
)
admin
.
add_view
(
view
)
admin
.
add_view
(
view
)
fill_db
(
Model1
,
Model2
)
fill_db
(
Model1
,
Model2
)
...
@@ -201,7 +202,8 @@ def test_column_editable_list():
...
@@ -201,7 +202,8 @@ def test_column_editable_list():
# Form - Test basic in-line edit functionality
# Form - Test basic in-line edit functionality
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
'test1-1'
:
'change-success-1'
,
'list_form_pk'
:
'1'
,
'test1'
:
'change-success-1'
,
})
})
data
=
rv
.
data
.
decode
(
'utf-8'
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'Record was successfully saved.'
==
data
)
ok_
(
'Record was successfully saved.'
==
data
)
...
@@ -213,32 +215,35 @@ def test_column_editable_list():
...
@@ -213,32 +215,35 @@ def test_column_editable_list():
# Test validation error
# Test validation error
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
'enum_field-1'
:
'problematic-input'
,
'list_form_pk'
:
'1'
,
'test1'
:
'longerthantwentycharacterslongerthantwentycharacterslongerthantwentycharacterslongerthantwentycharacters'
,
})
})
data
=
rv
.
data
.
decode
(
'utf-8'
)
eq_
(
rv
.
status_code
,
500
)
eq_
(
rv
.
status_code
,
500
)
# Test invalid primary key
# Test invalid primary key
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
'test1-1000'
:
'problematic-input'
,
'list_form_pk'
:
'1000'
,
'test1'
:
'problematic-input'
,
})
})
data
=
rv
.
data
.
decode
(
'utf-8'
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
eq_
(
rv
.
status_code
,
500
)
eq_
(
rv
.
status_code
,
500
)
# Test editing column not in column_editable_list
# Test editing column not in column_editable_list
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
'test2-1'
:
'problematic-input'
,
'list_form_pk'
:
'1'
,
'test2'
:
'problematic-input'
,
})
})
data
=
rv
.
data
.
decode
(
'utf-8'
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
eq_
(
rv
.
status_code
,
500
)
ok_
(
'problematic-input'
not
in
data
)
# Test in-line editing for relations
# Test in-line editing for relations
view
=
CustomModelView
(
Model2
,
view
=
CustomModelView
(
Model2
,
column_editable_list
=
[
'model1'
])
column_editable_list
=
[
'model1'
])
admin
.
add_view
(
view
)
admin
.
add_view
(
view
)
rv
=
client
.
post
(
'/admin/model2/ajax/update/'
,
data
=
{
rv
=
client
.
post
(
'/admin/model2/ajax/update/'
,
data
=
{
'model1-1'
:
'3'
,
'list_form_pk'
:
'1'
,
'model1'
:
'3'
,
})
})
data
=
rv
.
data
.
decode
(
'utf-8'
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'Record was successfully saved.'
==
data
)
ok_
(
'Record was successfully saved.'
==
data
)
...
...
flask_admin/tests/sqla/test_basic.py
View file @
6f4ef689
...
@@ -354,8 +354,7 @@ def test_column_editable_list():
...
@@ -354,8 +354,7 @@ def test_column_editable_list():
Model1
,
Model2
=
create_models
(
db
)
Model1
,
Model2
=
create_models
(
db
)
view
=
CustomModelView
(
Model1
,
db
.
session
,
view
=
CustomModelView
(
Model1
,
db
.
session
,
column_editable_list
=
[
column_editable_list
=
[
'test1'
,
'enum_field'
])
'test1'
,
'enum_field'
])
admin
.
add_view
(
view
)
admin
.
add_view
(
view
)
fill_db
(
db
,
Model1
,
Model2
)
fill_db
(
db
,
Model1
,
Model2
)
...
@@ -369,7 +368,8 @@ def test_column_editable_list():
...
@@ -369,7 +368,8 @@ def test_column_editable_list():
# Form - Test basic in-line edit functionality
# Form - Test basic in-line edit functionality
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
'test1-1'
:
'change-success-1'
,
'list_form_pk'
:
'1'
,
'test1'
:
'change-success-1'
,
})
})
data
=
rv
.
data
.
decode
(
'utf-8'
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'Record was successfully saved.'
==
data
)
ok_
(
'Record was successfully saved.'
==
data
)
...
@@ -381,32 +381,34 @@ def test_column_editable_list():
...
@@ -381,32 +381,34 @@ def test_column_editable_list():
# Test validation error
# Test validation error
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
'enum_field-1'
:
'problematic-input'
,
'list_form_pk'
:
'1'
,
'enum_field'
:
'problematic-input'
,
})
})
eq_
(
rv
.
status_code
,
500
)
eq_
(
rv
.
status_code
,
500
)
# Test invalid primary key
# Test invalid primary key
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
'test1-1000'
:
'problematic-input'
,
'list_form_pk'
:
'1000'
,
'test1'
:
'problematic-input'
,
})
})
data
=
rv
.
data
.
decode
(
'utf-8'
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
eq_
(
rv
.
status_code
,
500
)
eq_
(
rv
.
status_code
,
500
)
# Test editing column not in column_editable_list
# Test editing column not in column_editable_list
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
'test2-1'
:
'problematic-input'
,
'list_form_pk'
:
'1'
,
'test2'
:
'problematic-input'
,
})
})
data
=
rv
.
data
.
decode
(
'utf-8'
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
eq_
(
rv
.
status_code
,
500
)
ok_
(
'problematic-input'
not
in
data
)
# Test in-line editing for relations
# Test in-line editing for relations
view
=
CustomModelView
(
Model2
,
db
.
session
,
view
=
CustomModelView
(
Model2
,
db
.
session
,
column_editable_list
=
[
'model1'
])
column_editable_list
=
[
'model1'
])
admin
.
add_view
(
view
)
admin
.
add_view
(
view
)
rv
=
client
.
post
(
'/admin/model2/ajax/update/'
,
data
=
{
rv
=
client
.
post
(
'/admin/model2/ajax/update/'
,
data
=
{
'model1-1'
:
'3'
,
'list_form_pk'
:
'1'
,
'model1'
:
'3'
,
})
})
data
=
rv
.
data
.
decode
(
'utf-8'
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'Record was successfully saved.'
==
data
)
ok_
(
'Record was successfully saved.'
==
data
)
...
@@ -495,7 +497,8 @@ def test_editable_list_special_pks():
...
@@ -495,7 +497,8 @@ def test_editable_list_special_pks():
# Form - Test basic in-line edit functionality
# Form - Test basic in-line edit functionality
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
rv
=
client
.
post
(
'/admin/model1/ajax/update/'
,
data
=
{
'val1-1-1'
:
'change-success-1'
,
'list_form_pk'
:
'1-1'
,
'val1'
:
'change-success-1'
,
})
})
data
=
rv
.
data
.
decode
(
'utf-8'
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'Record was successfully saved.'
==
data
)
ok_
(
'Record was successfully saved.'
==
data
)
...
@@ -1511,8 +1514,8 @@ def test_form_onetoone():
...
@@ -1511,8 +1514,8 @@ def test_form_onetoone():
eq_
(
model1
.
model2
,
model2
)
eq_
(
model1
.
model2
,
model2
)
eq_
(
model2
.
model1
,
model1
)
eq_
(
model2
.
model1
,
model1
)
eq_
(
view1
.
_create_form_class
.
model2
.
kwargs
[
'widget'
]
.
multiple
,
False
)
eq_
(
view1
.
_create_form_class
.
model2
.
field_class
.
widget
.
multiple
,
False
)
eq_
(
view2
.
_create_form_class
.
model1
.
kwargs
[
'widget'
]
.
multiple
,
False
)
eq_
(
view2
.
_create_form_class
.
model1
.
field_class
.
widget
.
multiple
,
False
)
def
test_relations
():
def
test_relations
():
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment