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
eb37f32c
Commit
eb37f32c
authored
Dec 29, 2014
by
Paul Brown
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add editable list view
parent
ba4e10ce
Changes
20
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
2079 additions
and
114 deletions
+2079
-114
view.py
flask_admin/contrib/mongoengine/view.py
+52
-1
view.py
flask_admin/contrib/peewee/view.py
+55
-1
view.py
flask_admin/contrib/sqla/view.py
+56
-1
base.py
flask_admin/model/base.py
+126
-33
fields.py
flask_admin/model/fields.py
+55
-1
widgets.py
flask_admin/model/widgets.py
+78
-0
form-1.0.0.js
flask_admin/static/admin/js/form-1.0.0.js
+38
-1
bootstrap2-editable-1.5.1.css
...tatic/vendor/x-editable/css/bootstrap2-editable-1.5.1.css
+663
-0
bootstrap3-editable-1.5.1.css
...tatic/vendor/x-editable/css/bootstrap3-editable-1.5.1.css
+663
-0
clear.png
flask_admin/static/vendor/x-editable/img/clear.png
+0
-0
loading.gif
flask_admin/static/vendor/x-editable/img/loading.gif
+0
-0
bootstrap2-editable-1.5.1.min.js
...tic/vendor/x-editable/js/bootstrap2-editable-1.5.1.min.js
+7
-0
bootstrap3-editable-1.5.1.min.js
...tic/vendor/x-editable/js/bootstrap3-editable-1.5.1.min.js
+7
-0
lib.html
flask_admin/templates/bootstrap2/admin/lib.html
+6
-0
list.html
flask_admin/templates/bootstrap2/admin/model/list.html
+12
-3
lib.html
flask_admin/templates/bootstrap3/admin/lib.html
+13
-7
list.html
flask_admin/templates/bootstrap3/admin/model/list.html
+11
-3
test_basic.py
flask_admin/tests/mongoengine/test_basic.py
+76
-13
test_basic.py
flask_admin/tests/peeweemodel/test_basic.py
+77
-19
test_basic.py
flask_admin/tests/sqla/test_basic.py
+84
-31
No files found.
flask_admin/contrib/mongoengine/view.py
View file @
eb37f32c
...
...
@@ -6,13 +6,16 @@ from flask.ext.admin import expose
from
flask.ext.admin.babel
import
gettext
,
ngettext
,
lazy_gettext
from
flask.ext.admin.model
import
BaseModelView
from
flask.ext.admin._compat
import
iteritems
,
string_types
from
flask.ext.admin.actions
import
action
from
flask.ext.admin.model.fields
import
ListEditableFieldList
from
wtforms.fields.core
import
UnboundField
import
mongoengine
import
gridfs
from
mongoengine.connection
import
get_db
from
bson.objectid
import
ObjectId
from
flask.ext.admin.actions
import
action
from
.filters
import
FilterConverter
,
BaseMongoEngineFilter
from
.form
import
get_form
,
CustomModelConverter
from
.typefmt
import
DEFAULT_FORMATTERS
...
...
@@ -398,6 +401,23 @@ class ModelView(BaseModelView):
return
form_class
def
scaffold_list_form
(
self
):
"""
Create form for the list view editable columns.
"""
form_class
=
get_form
(
self
.
model
,
self
.
model_form_converter
(
self
),
base_class
=
self
.
form_base_class
,
only
=
self
.
column_editable_list
)
# iterate FormMeta to get unbound fields
field_dict
=
{}
for
name
,
field_object
in
iteritems
(
form_class
.
__dict__
):
if
not
name
.
startswith
(
'_'
)
and
isinstance
(
field_object
,
UnboundField
):
# wrap each field in the form from get_form in FieldList
field_dict
[
name
]
=
ListEditableFieldList
(
field_object
)
return
type
(
self
.
model
.
__name__
+
'Form'
,
(
self
.
form_base_class
,
),
field_dict
)
# AJAX foreignkey support
def
_create_ajax_loader
(
self
,
name
,
opts
):
return
create_ajax_loader
(
self
.
model
,
name
,
name
,
opts
)
...
...
@@ -545,6 +565,37 @@ class ModelView(BaseModelView):
return
True
def
update_list_model
(
self
,
form
):
"""
Update model from the list view.
Only supports updating a single field at a time.
:param form:
Form instance
"""
try
:
model
=
self
.
model
()
for
field
in
form
:
# FieldList's last_index will only be set if a field is submitted
# last_index will be the primary key of the updated record
if
getattr
(
field
,
'last_index'
,
None
):
record
=
self
.
get_one
(
field
.
last_index
)
setattr
(
record
,
field
.
name
,
field
.
data
.
pop
())
self
.
_on_model_change
(
form
,
model
,
False
)
record
.
save
()
self
.
after_model_change
(
form
,
model
,
False
)
return
True
except
Exception
as
ex
:
if
not
self
.
handle_view_exception
(
ex
):
log
.
exception
(
gettext
(
'Failed to update record.
%(error)
s'
,
error
=
str
(
ex
)),
'error'
)
self
.
session
.
rollback
()
# Error: Unable to update database or no records were changed.
return
False
def
delete_model
(
self
,
model
):
"""
Delete model helper
...
...
flask_admin/contrib/peewee/view.py
View file @
eb37f32c
...
...
@@ -2,7 +2,7 @@ import logging
from
flask
import
flash
from
flask.ext.admin._compat
import
string_types
from
flask.ext.admin._compat
import
string_types
,
iteritems
from
flask.ext.admin.babel
import
gettext
,
ngettext
,
lazy_gettext
from
flask.ext.admin.model
import
BaseModelView
...
...
@@ -11,6 +11,9 @@ from peewee import PrimaryKeyField, ForeignKeyField, Field, CharField, TextField
from
flask.ext.admin.actions
import
action
from
flask.ext.admin.contrib.peewee
import
filters
from
flask.ext.admin.model.fields
import
ListEditableFieldList
from
wtforms.fields.core
import
UnboundField
from
.form
import
get_form
,
CustomModelConverter
,
InlineModelConverter
,
save_inline
from
.tools
import
get_primary_key
,
parse_like_term
from
.ajax
import
create_ajax_loader
...
...
@@ -237,6 +240,23 @@ class ModelView(BaseModelView):
return
form_class
def
scaffold_list_form
(
self
):
"""
Create form for the list view editable columns.
"""
form_class
=
get_form
(
self
.
model
,
self
.
model_form_converter
(
self
),
base_class
=
self
.
form_base_class
,
only
=
self
.
column_editable_list
)
# iterate FormMeta to get unbound fields
field_dict
=
{}
for
name
,
field_object
in
iteritems
(
form_class
.
__dict__
):
if
not
name
.
startswith
(
'_'
)
and
isinstance
(
field_object
,
UnboundField
):
# wrap each field in the form from get_form in FieldList
field_dict
[
name
]
=
ListEditableFieldList
(
field_object
)
return
type
(
self
.
model
.
__name__
+
'Form'
,
(
self
.
form_base_class
,
),
field_dict
)
def
scaffold_inline_form_models
(
self
,
form_class
):
converter
=
self
.
model_form_converter
(
self
)
inline_converter
=
self
.
inline_model_form_converter
(
self
)
...
...
@@ -382,6 +402,40 @@ class ModelView(BaseModelView):
return
True
def
update_list_model
(
self
,
form
):
"""
Update model from the list view.
Only supports updating a single field at a time.
:param form:
Form instance
"""
try
:
model
=
self
.
model
()
for
field
in
form
:
# FieldList's last_index will only be set if a field is submitted
# last_index will be the primary key of the updated record
if
getattr
(
field
,
'last_index'
,
None
):
record
=
self
.
get_one
(
field
.
last_index
)
setattr
(
record
,
field
.
name
,
field
.
data
.
pop
())
self
.
_on_model_change
(
form
,
model
,
False
)
record
.
save
()
# For peewee have to save inline forms after model was saved
save_inline
(
form
,
model
)
self
.
after_model_change
(
form
,
model
,
False
)
return
True
except
Exception
as
ex
:
if
not
self
.
handle_view_exception
(
ex
):
log
.
exception
(
gettext
(
'Failed to update record.
%(error)
s'
,
error
=
str
(
ex
)),
'error'
)
self
.
session
.
rollback
()
# Error: Unable to update database or no records were changed.
return
False
def
delete_model
(
self
,
model
):
try
:
self
.
on_model_delete
(
model
)
...
...
flask_admin/contrib/sqla/view.py
View file @
eb37f32c
...
...
@@ -8,12 +8,15 @@ from sqlalchemy.exc import IntegrityError
from
flask
import
flash
from
flask.ext.admin._compat
import
string_types
from
flask.ext.admin._compat
import
string_types
,
iteritems
from
flask.ext.admin.babel
import
gettext
,
ngettext
,
lazy_gettext
from
flask.ext.admin.model
import
BaseModelView
from
flask.ext.admin.actions
import
action
from
flask.ext.admin._backwards
import
ObsoleteAttr
from
flask.ext.admin.model.fields
import
ListEditableFieldList
from
wtforms.fields.core
import
UnboundField
from
flask.ext.admin.contrib.sqla
import
form
,
filters
,
tools
from
.typefmt
import
DEFAULT_FORMATTERS
from
.tools
import
get_query_for_ids
...
...
@@ -611,6 +614,27 @@ class ModelView(BaseModelView):
return
form_class
def
scaffold_list_form
(
self
):
"""
Create form for the list view editable columns.
The form is created using the existing get_form(),
but each field is wrapped in a WTForms FieldList.
"""
converter
=
self
.
model_form_converter
(
self
.
session
,
self
)
form_class
=
form
.
get_form
(
self
.
model
,
converter
,
base_class
=
self
.
form_base_class
,
only
=
self
.
column_editable_list
)
# iterate FormMeta to get unbound fields
field_dict
=
{}
for
name
,
field_object
in
iteritems
(
form_class
.
__dict__
):
if
not
name
.
startswith
(
'_'
)
and
isinstance
(
field_object
,
UnboundField
):
# wrap each field in the form from get_form in FieldList
field_dict
[
name
]
=
ListEditableFieldList
(
field_object
)
return
type
(
self
.
model
.
__name__
+
'Form'
,
(
self
.
form_base_class
,
),
field_dict
)
def
scaffold_inline_form_models
(
self
,
form_class
):
"""
Contribute inline models to the form
...
...
@@ -898,6 +922,37 @@ class ModelView(BaseModelView):
return
True
def
update_list_model
(
self
,
form
):
"""
Update model from the list view.
Only supports updating a single field at a time.
:param form:
Form instance
"""
try
:
model
=
self
.
model
()
for
field
in
form
:
# FieldList's last_index will only be set if a field is submitted
# last_index will be the primary key of the updated record
if
getattr
(
field
,
'last_index'
,
None
):
record
=
self
.
session
.
query
(
self
.
model
)
.
get
(
field
.
last_index
)
setattr
(
record
,
field
.
name
,
field
.
data
.
pop
())
self
.
_on_model_change
(
form
,
model
,
False
)
self
.
session
.
commit
()
self
.
after_model_change
(
form
,
model
,
False
)
return
True
except
Exception
as
ex
:
if
not
self
.
handle_view_exception
(
ex
):
log
.
exception
(
gettext
(
'Failed to update record.
%(error)
s'
,
error
=
str
(
ex
)),
'error'
)
self
.
session
.
rollback
()
# Error: Unable to update database or no records were changed.
return
False
def
delete_model
(
self
,
model
):
"""
Delete model.
...
...
flask_admin/model/base.py
View file @
eb37f32c
...
...
@@ -11,7 +11,8 @@ from flask.ext.admin.base import BaseView, expose
from
flask.ext.admin.form
import
BaseForm
,
FormOpts
,
rules
from
flask.ext.admin.model
import
filters
,
typefmt
from
flask.ext.admin.actions
import
ActionsMixin
from
flask.ext.admin.helpers
import
get_form_data
,
validate_form_on_submit
,
get_redirect_target
from
flask.ext.admin.helpers
import
(
get_form_data
,
validate_form_on_submit
,
get_redirect_target
,
is_form_submitted
)
from
flask.ext.admin.tools
import
rec_getattr
from
flask.ext.admin._backwards
import
ObsoleteAttr
from
flask.ext.admin._compat
import
iteritems
,
OrderedDict
,
as_unicode
...
...
@@ -264,6 +265,16 @@ class BaseModelView(BaseView, ActionsMixin):
column_searchable_list = ('name', 'email')
"""
column_editable_list
=
None
"""
Collection of the columns which can be edited from the list view.
For example::
class MyModelView(BaseModelView):
column_editable_list = ('name', 'last_name')
"""
column_choices
=
None
"""
Map choices to columns in list view
...
...
@@ -579,6 +590,12 @@ class BaseModelView(BaseView, ActionsMixin):
self
.
_create_form_class
=
self
.
get_create_form
()
self
.
_edit_form_class
=
self
.
get_edit_form
()
# List View In-Line Editing
if
self
.
column_editable_list
:
self
.
_list_form_class
=
self
.
scaffold_list_form
()
else
:
self
.
column_editable_list
=
{}
def
_refresh_filters_cache
(
self
):
self
.
_filters
=
self
.
get_filters
()
...
...
@@ -833,6 +850,12 @@ class BaseModelView(BaseView, ActionsMixin):
"""
raise
NotImplementedError
(
'Please implement scaffold_form method'
)
def
scaffold_list_form
(
self
):
"""
Create form class for list view in-line editing.
"""
raise
NotImplementedError
(
'Please implement scaffold_list_form method'
)
def
get_form
(
self
):
"""
Get form class.
...
...
@@ -879,6 +902,14 @@ class BaseModelView(BaseView, ActionsMixin):
"""
return
self
.
_edit_form_class
(
get_form_data
(),
obj
=
obj
)
def
list_form
(
self
,
obj
=
None
):
"""
Instantiate model editing form for list view and return it.
Override to implement custom behavior.
"""
return
self
.
_list_form_class
(
get_form_data
(),
obj
=
obj
)
def
validate_form
(
self
,
form
):
"""
Validate the form on submit.
...
...
@@ -898,6 +929,15 @@ class BaseModelView(BaseView, ActionsMixin):
"""
return
name
in
self
.
_sortable_columns
def
is_editable
(
self
,
name
):
"""
Verify if column is editable.
:param name:
Column name.
"""
return
name
in
self
.
column_editable_list
def
_get_column_by_idx
(
self
,
idx
):
"""
Return column index by
...
...
@@ -1074,6 +1114,15 @@ class BaseModelView(BaseView, ActionsMixin):
"""
raise
NotImplementedError
()
def
update_list_model
(
self
,
form
,
model
):
"""
Update model from the list view.
:param form:
Form instance
"""
raise
NotImplementedError
()
def
delete_model
(
self
,
model
):
"""
Delete model.
...
...
@@ -1242,11 +1291,45 @@ class BaseModelView(BaseView, ActionsMixin):
raise
NotImplementedError
()
# Views
@
expose
(
'/'
)
@
expose
(
'/'
,
methods
=
(
'POST'
,
'GET'
)
)
def
index_view
(
self
):
"""
List view
"""
if
self
.
column_editable_list
:
form
=
self
.
list_form
()
# prevent validation issues due to submitting a single field
# delete all fields except the field being submitted
if
is_form_submitted
():
for
field
in
form
:
# only submitted fields have last_index
if
getattr
(
field
,
'last_index'
,
None
):
pass
elif
field
.
name
==
'csrf_token'
:
pass
else
:
form
.
__delitem__
(
field
.
name
)
if
self
.
validate_form
(
form
):
if
self
.
update_list_model
(
form
):
return
gettext
(
'Record was successfully saved.'
)
else
:
# No records changed, or error saving to database.
return
gettext
(
'Failed to update record.
%(error)
s'
,
error
=
''
),
500
if
form
.
errors
:
for
field
in
form
:
for
error
in
field
.
errors
:
# return error to x-editable
if
isinstance
(
error
,
list
):
return
", "
.
join
(
error
),
500
else
:
return
error
,
500
else
:
form
=
None
# Grab parameters from URL
view_args
=
self
.
_get_list_extra_args
()
...
...
@@ -1289,37 +1372,47 @@ class BaseModelView(BaseView, ActionsMixin):
search
=
None
,
filters
=
None
))
return
self
.
render
(
self
.
list_template
,
data
=
data
,
# List
list_columns
=
self
.
_list_columns
,
sortable_columns
=
self
.
_sortable_columns
,
# Stuff
enumerate
=
enumerate
,
get_pk_value
=
self
.
get_pk_value
,
get_value
=
self
.
get_list_value
,
return_url
=
self
.
_get_list_url
(
view_args
),
# Pagination
count
=
count
,
pager_url
=
pager_url
,
num_pages
=
num_pages
,
page
=
view_args
.
page
,
# Sorting
sort_column
=
view_args
.
sort
,
sort_desc
=
view_args
.
sort_desc
,
sort_url
=
sort_url
,
# Search
search_supported
=
self
.
_search_supported
,
clear_search_url
=
clear_search_url
,
search
=
view_args
.
search
,
# Filters
filters
=
self
.
_filters
,
filter_groups
=
self
.
_filter_groups
,
active_filters
=
view_args
.
filters
,
# Actions
actions
=
actions
,
actions_confirmation
=
actions_confirmation
)
return
self
.
render
(
self
.
list_template
,
data
=
data
,
form
=
form
,
# List
list_columns
=
self
.
_list_columns
,
sortable_columns
=
self
.
_sortable_columns
,
editable_columns
=
self
.
column_editable_list
,
# Pagination
count
=
count
,
pager_url
=
pager_url
,
num_pages
=
num_pages
,
page
=
view_args
.
page
,
# Sorting
sort_column
=
view_args
.
sort
,
sort_desc
=
view_args
.
sort_desc
,
sort_url
=
sort_url
,
# Search
search_supported
=
self
.
_search_supported
,
clear_search_url
=
clear_search_url
,
search
=
view_args
.
search
,
# Filters
filters
=
self
.
_filters
,
filter_groups
=
self
.
_filter_groups
,
active_filters
=
view_args
.
filters
,
# Actions
actions
=
actions
,
actions_confirmation
=
actions_confirmation
,
# Misc
enumerate
=
enumerate
,
get_pk_value
=
self
.
get_pk_value
,
get_value
=
self
.
get_list_value
,
return_url
=
self
.
_get_list_url
(
view_args
),
)
@
expose
(
'/new/'
,
methods
=
(
'GET'
,
'POST'
))
def
create_view
(
self
):
...
...
flask_admin/model/fields.py
View file @
eb37f32c
...
...
@@ -3,8 +3,14 @@ import itertools
from
wtforms.validators
import
ValidationError
from
wtforms.fields
import
FieldList
,
FormField
,
SelectFieldBase
try
:
from
wtforms.fields
import
_unset_value
as
unset_value
except
ImportError
:
from
wtforms.utils
import
unset_value
from
flask.ext.admin._compat
import
iteritems
from
.widgets
import
InlineFieldListWidget
,
InlineFormWidget
,
AjaxSelect2Widget
from
.widgets
import
(
InlineFieldListWidget
,
InlineFormWidget
,
AjaxSelect2Widget
,
XEditableWidget
)
class
InlineFieldList
(
FieldList
):
...
...
@@ -120,6 +126,54 @@ class InlineModelFormField(FormField):
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
k
in
formdata
:
if
k
.
startswith
(
prefix
):
k
=
k
[
offset
:]
.
split
(
'-'
,
1
)[
0
]
# removed "if k.isdigit():"
yield
k
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
class
AjaxSelectField
(
SelectFieldBase
):
"""
Ajax Model Select Field
...
...
flask_admin/model/widgets.py
View file @
eb37f32c
...
...
@@ -61,3 +61,81 @@ class AjaxSelect2Widget(object):
kwargs
.
setdefault
(
'data-placeholder'
,
placeholder
)
return
HTMLString
(
'<input
%
s>'
%
html_params
(
name
=
field
.
name
,
**
kwargs
))
class
XEditableWidget
(
object
):
"""
WTForms widget that provides in-line editing for the list view.
Determines how to display the x-editable/ajax form based on the
field inside of the FieldList (StringField, IntegerField, etc).
"""
def
__call__
(
self
,
field
,
**
kwargs
):
value
=
kwargs
.
pop
(
"value"
,
""
)
kwargs
.
setdefault
(
'data-role'
,
'x-editable'
)
kwargs
.
setdefault
(
'data-url'
,
'./'
)
kwargs
.
setdefault
(
'id'
,
field
.
id
)
kwargs
.
setdefault
(
'name'
,
field
.
name
)
kwargs
.
setdefault
(
'href'
,
'#'
)
if
not
kwargs
.
get
(
'pk'
):
raise
Exception
(
'pk required'
)
kwargs
[
'data-pk'
]
=
str
(
kwargs
.
pop
(
"pk"
))
kwargs
[
'data-csrf'
]
=
kwargs
.
pop
(
"csrf"
,
""
)
# get first entry from FieldList to determine field type
subfield
=
field
.
entries
[
0
]
if
subfield
.
type
==
'StringField'
:
kwargs
[
'data-type'
]
=
'text'
elif
subfield
.
type
==
'TextAreaField'
:
kwargs
[
'data-type'
]
=
'textarea'
kwargs
[
'data-rows'
]
=
'5'
elif
subfield
.
type
==
'BooleanField'
:
kwargs
[
'data-type'
]
=
'select'
# data-source = dropdown options
kwargs
[
'data-source'
]
=
{
''
:
'False'
,
'1'
:
'True'
}
kwargs
[
'data-role'
]
=
'x-editable-boolean'
elif
subfield
.
type
==
'Select2Field'
:
kwargs
[
'data-type'
]
=
'select'
kwargs
[
'data-source'
]
=
dict
(
subfield
.
choices
)
elif
subfield
.
type
in
[
'QuerySelectField'
,
'ModelSelectField'
]:
kwargs
[
'data-type'
]
=
'select'
# MongoEngine throws an error on blank object names
# this prevents "TypeError: cannot create 'NoneType' instances"
choices
=
{}
for
choice
in
subfield
:
try
:
choices
[
str
(
choice
.
_value
())]
=
str
(
choice
.
label
.
text
)
except
TypeError
:
choices
[
str
(
choice
.
_value
())]
=
""
kwargs
[
'data-source'
]
=
choices
elif
subfield
.
type
==
'DateField'
:
kwargs
[
'data-type'
]
=
'combodate'
kwargs
[
'data-format'
]
=
'YYYY-MM-DD'
kwargs
[
'data-template'
]
=
'YYYY-MM-DD'
elif
subfield
.
type
==
'DateTimeField'
:
kwargs
[
'data-type'
]
=
'combodate'
kwargs
[
'data-format'
]
=
'YYYY-MM-DD HH:mm:ss'
kwargs
[
'data-template'
]
=
'YYYY-MM-DD HH:mm:ss'
# x-editable-combodate uses 1 minute increments
kwargs
[
'data-role'
]
=
'x-editable-combodate'
elif
subfield
.
type
==
'TimeField'
:
kwargs
[
'data-type'
]
=
'combodate'
kwargs
[
'data-format'
]
=
'HH:mm:ss'
kwargs
[
'data-template'
]
=
'HH:mm:ss'
kwargs
[
'data-role'
]
=
'x-editable-combodate'
elif
subfield
.
type
==
'IntegerField'
:
kwargs
[
'data-type'
]
=
'number'
elif
subfield
.
type
in
[
'DecimalField'
,
'FloatField'
]:
kwargs
[
'data-type'
]
=
'number'
kwargs
[
'data-step'
]
=
'any'
else
:
raise
Exception
(
'Unsupported field type:
%
s'
%
(
type
(
subfield
),))
return
HTMLString
(
'<a
%
s>
%
s</a>'
%
(
html_params
(
**
kwargs
),
value
)
)
flask_admin/static/admin/js/form-1.0.0.js
View file @
eb37f32c
...
...
@@ -241,6 +241,17 @@
return
true
;
}
// make x-editable's POST act like a normal FieldList field
// for x-editable, x-editable-combodate, and x-editable-boolean cases
var
overrideXeditableParams
=
function
(
params
)
{
var
newParams
=
{};
newParams
[
params
.
name
+
'-'
+
params
.
pk
]
=
params
.
value
;
if
(
$
(
this
).
data
(
'csrf'
))
{
newParams
[
'csrf_token'
]
=
$
(
this
).
data
(
'csrf'
);
}
return
newParams
;
}
switch
(
name
)
{
case
'select2'
:
var
opts
=
{
...
...
@@ -390,6 +401,32 @@
case
'leaflet'
:
processLeafletWidget
(
$el
,
name
);
return
true
;
case
'x-editable'
:
$el
.
editable
({
params
:
overrideXeditableParams
});
return
true
;
case
'x-editable-combodate'
:
$el
.
editable
({
params
:
overrideXeditableParams
,
combodate
:
{
// prevent minutes from showing in 5 minute increments
minuteStep
:
1
}
});
return
true
;
case
'x-editable-boolean'
:
$el
.
editable
({
params
:
overrideXeditableParams
,
display
:
function
(
value
,
sourceData
,
response
)
{
// display new boolean value as an icon
if
(
response
)
{
if
(
value
==
'1'
)
{
$
(
this
).
html
(
'<span class="glyphicon glyphicon-ok-circle icon-ok-circle"></span>'
);
}
else
{
$
(
this
).
html
(
'<span class="glyphicon glyphicon-minus-sign icon-minus-sign"></span>'
);
}
}
}
});
}
};
...
...
@@ -463,7 +500,7 @@
this
.
applyGlobalStyles
=
function
(
parent
)
{
var
self
=
this
;
$
(
':input[data-role]'
,
parent
).
each
(
function
()
{
$
(
':input[data-role]
, a[data-role]
'
,
parent
).
each
(
function
()
{
var
$el
=
$
(
this
);
self
.
applyStyle
(
$el
,
$el
.
attr
(
'data-role'
));
});
...
...
flask_admin/static/vendor/x-editable/css/bootstrap2-editable-1.5.1.css
0 → 100644
View file @
eb37f32c
This diff is collapsed.
Click to expand it.
flask_admin/static/vendor/x-editable/css/bootstrap3-editable-1.5.1.css
0 → 100644
View file @
eb37f32c
This diff is collapsed.
Click to expand it.
flask_admin/static/vendor/x-editable/img/clear.png
0 → 100644
View file @
eb37f32c
509 Bytes
flask_admin/static/vendor/x-editable/img/loading.gif
0 → 100644
View file @
eb37f32c
1.81 KB
flask_admin/static/vendor/x-editable/js/bootstrap2-editable-1.5.1.min.js
0 → 100644
View file @
eb37f32c
This diff is collapsed.
Click to expand it.
flask_admin/static/vendor/x-editable/js/bootstrap3-editable-1.5.1.min.js
0 → 100644
View file @
eb37f32c
This diff is collapsed.
Click to expand it.
flask_admin/templates/bootstrap2/admin/lib.html
View file @
eb37f32c
...
...
@@ -178,6 +178,9 @@
<link
href=
"{{ admin_static.url(filename='vendor/leaflet/leaflet.css') }}"
rel=
"stylesheet"
>
<link
href=
"{{ admin_static.url(filename='vendor/leaflet/leaflet.draw.css') }}"
rel=
"stylesheet"
>
{% endif %}
{% if editable_columns %}
<link
href=
"{{ admin_static.url(filename='vendor/x-editable/css/bootstrap2-editable-1.5.1.css') }}"
rel=
"stylesheet"
>
{% endif %}
{% endmacro %}
{% macro form_js() %}
...
...
@@ -189,5 +192,8 @@
<script
src=
"{{ admin_static.url(filename='vendor/leaflet/leaflet.draw.js') }}"
></script>
{% endif %}
<script
src=
"{{ admin_static.url(filename='vendor/bootstrap-daterangepicker/daterangepicker.js') }}"
></script>
{% if editable_columns %}
<script
src=
"{{ admin_static.url(filename='vendor/x-editable/js/bootstrap2-editable-1.5.1.min.js') }}"
></script>
{% endif %}
<script
src=
"{{ admin_static.url(filename='admin/js/form-1.0.0.js') }}"
></script>
{% endmacro %}
flask_admin/templates/bootstrap2/admin/model/list.html
View file @
eb37f32c
...
...
@@ -119,8 +119,17 @@
{% endblock %}
</td>
{% endblock %}
{% for c, name in list_columns %}
<td>
{{ get_value(row, c) }}
</td>
{% if admin_view.is_editable(c) %}
{% if form.csrf_token %}
<td>
{{ form[c](pk=get_pk_value(row), value=get_value(row, c), csrf=form.csrf_token._value()) }}
</td>
{% else %}
<td>
{{ form[c](pk=get_pk_value(row), value=get_value(row, c)) }}
</td>
{% endif %}
{% else %}
<td>
{{ get_value(row, c) }}
</td>
{% endif %}
{% endfor %}
{% endblock %}
</tr>
...
...
@@ -148,8 +157,8 @@
<script
src=
"{{ admin_static.url(filename='admin/js/filters-1.0.0.js') }}"
></script>
{{ actionlib.script(_gettext('Please select at least one record.'),
actions,
actions_confirmation) }}
actions,
actions_confirmation) }}
<script
language=
"javascript"
>
(
function
(
$
)
{
...
...
flask_admin/templates/bootstrap3/admin/lib.html
View file @
eb37f32c
...
...
@@ -147,13 +147,13 @@
<hr>
<div
class=
"form-group"
>
<div
class=
"col-md-offset-2 col-md-10 submit-row"
>
<input
type=
"submit"
class=
"btn btn-primary"
value=
"{{ _gettext('Submit') }}"
/>
{% if extra %}
{{ extra }}
{% endif %}
{% if cancel_url %}
<a
href=
"{{ cancel_url }}"
class=
"btn btn-danger"
role=
"button"
>
{{ _gettext('Cancel') }}
</a>
{% endif %}
<input
type=
"submit"
class=
"btn btn-primary"
value=
"{{ _gettext('Submit') }}"
/>
{% if extra %}
{{ extra }}
{% endif %}
{% if cancel_url %}
<a
href=
"{{ cancel_url }}"
class=
"btn btn-danger"
role=
"button"
>
{{ _gettext('Cancel') }}
</a>
{% endif %}
</div>
</div>
{% endmacro %}
...
...
@@ -173,6 +173,9 @@
<link
href=
"{{ admin_static.url(filename='vendor/leaflet/leaflet.css') }}"
rel=
"stylesheet"
>
<link
href=
"{{ admin_static.url(filename='vendor/leaflet/leaflet.draw.css') }}"
rel=
"stylesheet"
>
{% endif %}
{% if editable_columns %}
<link
href=
"{{ admin_static.url(filename='vendor/x-editable/css/bootstrap3-editable-1.5.1.css') }}"
rel=
"stylesheet"
>
{% endif %}
{% endmacro %}
{% macro form_js() %}
...
...
@@ -184,5 +187,8 @@
<script
src=
"{{ admin_static.url(filename='vendor/leaflet/leaflet.draw.js') }}"
></script>
{% endif %}
<script
src=
"{{ admin_static.url(filename='vendor/bootstrap-daterangepicker/daterangepicker.js') }}"
></script>
{% if editable_columns %}
<script
src=
"{{ admin_static.url(filename='vendor/x-editable/js/bootstrap3-editable-1.5.1.min.js') }}"
></script>
{% endif %}
<script
src=
"{{ admin_static.url(filename='admin/js/form-1.0.0.js') }}"
></script>
{% endmacro %}
flask_admin/templates/bootstrap3/admin/model/list.html
View file @
eb37f32c
...
...
@@ -120,7 +120,15 @@
</td>
{% endblock %}
{% for c, name in list_columns %}
<td>
{{ get_value(row, c) }}
</td>
{% if admin_view.is_editable(c) %}
{% if form.csrf_token %}
<td>
{{ form[c](pk=get_pk_value(row), value=get_value(row, c), csrf=form.csrf_token._value()) }}
</td>
{% else %}
<td>
{{ form[c](pk=get_pk_value(row), value=get_value(row, c)) }}
</td>
{% endif %}
{% else %}
<td>
{{ get_value(row, c) }}
</td>
{% endif %}
{% endfor %}
{% endblock %}
</tr>
...
...
@@ -148,8 +156,8 @@
{{ lib.form_js() }}
{{ actionlib.script(_gettext('Please select at least one record.'),
actions,
actions_confirmation) }}
actions,
actions_confirmation) }}
<script
language=
"javascript"
>
(
function
(
$
)
{
...
...
flask_admin/tests/mongoengine/test_basic.py
View file @
eb37f32c
...
...
@@ -52,6 +52,22 @@ def create_models(db):
return
Model1
,
Model2
def
fill_db
(
Model1
,
Model2
):
Model1
(
'test1_val_1'
,
'test2_val_1'
)
.
save
()
Model1
(
'test1_val_2'
,
'test2_val_2'
)
.
save
()
Model1
(
'test1_val_3'
,
'test2_val_3'
)
.
save
()
Model1
(
'test1_val_4'
,
'test2_val_4'
)
.
save
()
Model1
(
None
,
'empty_obj'
)
.
save
()
Model2
(
'string_field_val_1'
,
None
,
None
)
.
save
()
Model2
(
'string_field_val_2'
,
None
,
None
)
.
save
()
Model2
(
'string_field_val_3'
,
5000
,
25.9
)
.
save
()
Model2
(
'string_field_val_4'
,
9000
,
75.5
)
.
save
()
Model1
(
'datetime_obj1'
,
datetime_field
=
datetime
(
2014
,
4
,
3
,
1
,
9
,
0
))
.
save
()
Model1
(
'datetime_obj2'
,
datetime_field
=
datetime
(
2013
,
3
,
2
,
0
,
8
,
0
))
.
save
()
def
test_model
():
app
,
db
,
admin
=
setup
()
...
...
@@ -124,25 +140,72 @@ def test_model():
eq_
(
rv
.
status_code
,
302
)
eq_
(
Model1
.
objects
.
count
(),
0
)
def
test_column_editable_list
():
app
,
db
,
admin
=
setup
()
Model1
,
Model2
=
create_models
(
db
)
view
=
CustomModelView
(
Model1
,
column_editable_list
=
[
'test1'
,
'datetime_field'
])
admin
.
add_view
(
view
)
fill_db
(
Model1
,
Model2
)
client
=
app
.
test_client
()
# Test in-line edit field rendering
rv
=
client
.
get
(
'/admin/model1/'
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'data-role="x-editable"'
in
data
)
# Form - Test basic in-line edit functionality
obj1
=
Model1
.
objects
.
get
(
test1
=
'test1_val_3'
)
rv
=
client
.
post
(
'/admin/model1/'
,
data
=
{
'test1-'
+
str
(
obj1
.
id
):
'change-success-1'
,
})
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'Record was successfully saved.'
==
data
)
# confirm the value has changed
rv
=
client
.
get
(
'/admin/model1/'
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'change-success-1'
in
data
)
# Test errors
obj2
=
Model1
.
objects
.
get
(
test1
=
'datetime_obj1'
)
rv
=
client
.
post
(
'/admin/model1/'
,
data
=
{
'datetime_field-'
+
str
(
obj2
.
id
):
'problematic-input'
,
})
eq_
(
rv
.
status_code
,
500
)
view
=
CustomModelView
(
Model2
,
column_editable_list
=
[
'model1'
])
admin
.
add_view
(
view
)
# Test in-line editing for relations
obj3
=
Model2
.
objects
.
get
(
string_field
=
'string_field_val_1'
)
rv
=
client
.
post
(
'/admin/model2/'
,
data
=
{
'model1-'
+
str
(
obj3
.
id
):
str
(
obj1
.
id
),
})
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'Record was successfully saved.'
==
data
)
# confirm the value has changed
rv
=
client
.
get
(
'/admin/model2/'
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'test1_val_1'
in
data
)
def
test_column_filters
():
app
,
db
,
admin
=
setup
()
Model1
,
Model2
=
create_models
(
db
)
# fill DB with values
Model1
(
'test1_val_1'
,
'test2_val_1'
)
.
save
()
Model1
(
'test1_val_2'
,
'test2_val_2'
)
.
save
()
Model1
(
'test1_val_3'
,
'test2_val_3'
)
.
save
()
Model1
(
'test1_val_4'
,
'test2_val_4'
)
.
save
()
Model1
(
None
,
'empty_obj'
)
.
save
()
Model2
(
'string_field_val_1'
,
None
,
None
)
.
save
()
Model2
(
'string_field_val_2'
,
None
,
None
)
.
save
()
Model2
(
'string_field_val_3'
,
5000
,
25.9
)
.
save
()
Model2
(
'string_field_val_4'
,
9000
,
75.5
)
.
save
()
Model1
(
'datetime_obj1'
,
datetime_field
=
datetime
(
2014
,
4
,
3
,
1
,
9
,
0
))
.
save
()
Model1
(
'datetime_obj2'
,
datetime_field
=
datetime
(
2013
,
3
,
2
,
0
,
8
,
0
))
.
save
()
fill_db
(
Model1
,
Model2
)
# Test string filter
view
=
CustomModelView
(
Model1
,
column_filters
=
[
'test1'
])
...
...
flask_admin/tests/peeweemodel/test_basic.py
View file @
eb37f32c
...
...
@@ -63,25 +63,49 @@ def create_models(db):
class
Model2
(
BaseModel
):
def
__init__
(
self
,
char_field
=
None
,
int_field
=
None
,
float_field
=
None
,
bool_field
=
0
):
bool_field
=
0
,
model1
=
None
):
super
(
Model2
,
self
)
.
__init__
()
self
.
char_field
=
char_field
self
.
int_field
=
int_field
self
.
float_field
=
float_field
self
.
bool_field
=
bool_field
self
.
model1
=
model1
char_field
=
peewee
.
CharField
(
max_length
=
20
)
int_field
=
peewee
.
IntegerField
(
null
=
True
)
float_field
=
peewee
.
FloatField
(
null
=
True
)
bool_field
=
peewee
.
BooleanField
()
# Relation
model1
=
peewee
.
ForeignKeyField
(
Model1
,
null
=
True
)
Model1
.
create_table
()
Model2
.
create_table
()
return
Model1
,
Model2
def
fill_db
(
Model1
,
Model2
):
Model1
(
'test1_val_1'
,
'test2_val_1'
)
.
save
()
Model1
(
'test1_val_2'
,
'test2_val_2'
)
.
save
()
Model1
(
'test1_val_3'
,
'test2_val_3'
)
.
save
()
Model1
(
'test1_val_4'
,
'test2_val_4'
)
.
save
()
Model1
(
None
,
'empty_obj'
)
.
save
()
Model2
(
'char_field_val_1'
,
None
,
None
)
.
save
()
Model2
(
'char_field_val_2'
,
None
,
None
)
.
save
()
Model2
(
'char_field_val_3'
,
5000
,
25.9
)
.
save
()
Model2
(
'char_field_val_4'
,
9000
,
75.5
)
.
save
()
Model1
(
'date_obj1'
,
date_field
=
date
(
2014
,
11
,
17
))
.
save
()
Model1
(
'date_obj2'
,
date_field
=
date
(
2013
,
10
,
16
))
.
save
()
Model1
(
'timeonly_obj1'
,
timeonly_field
=
time
(
11
,
10
,
9
))
.
save
()
Model1
(
'timeonly_obj2'
,
timeonly_field
=
time
(
10
,
9
,
8
))
.
save
()
Model1
(
'datetime_obj1'
,
datetime_field
=
datetime
(
2014
,
4
,
3
,
1
,
9
,
0
))
.
save
()
Model1
(
'datetime_obj2'
,
datetime_field
=
datetime
(
2013
,
3
,
2
,
0
,
8
,
0
))
.
save
()
def
test_model
():
app
,
db
,
admin
=
setup
()
Model1
,
Model2
=
create_models
(
db
)
...
...
@@ -153,29 +177,63 @@ def test_model():
eq_
(
rv
.
status_code
,
302
)
eq_
(
Model1
.
select
()
.
count
(),
0
)
def
test_column_editable_list
():
app
,
db
,
admin
=
setup
()
Model1
,
Model2
=
create_models
(
db
)
view
=
CustomModelView
(
Model1
,
column_editable_list
=
[
'test1'
,
'enum_field'
])
admin
.
add_view
(
view
)
fill_db
(
Model1
,
Model2
)
client
=
app
.
test_client
()
# Test in-line edit field rendering
rv
=
client
.
get
(
'/admin/model1/'
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'data-role="x-editable"'
in
data
)
# Form - Test basic in-line edit functionality
rv
=
client
.
post
(
'/admin/model1/'
,
data
=
{
'test1-1'
:
'change-success-1'
,
})
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'Record was successfully saved.'
==
data
)
# ensure the value has changed
rv
=
client
.
get
(
'/admin/model1/'
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'change-success-1'
in
data
)
# Test errors
rv
=
client
.
post
(
'/admin/model1/'
,
data
=
{
'enum_field-1'
:
'problematic-input'
,
})
eq_
(
rv
.
status_code
,
500
)
view
=
CustomModelView
(
Model2
,
column_editable_list
=
[
'model1'
])
admin
.
add_view
(
view
)
# Test in-line editing for relations
rv
=
client
.
post
(
'/admin/model2/'
,
data
=
{
'model1-1'
:
'3'
,
})
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'Record was successfully saved.'
==
data
)
def
test_column_filters
():
app
,
db
,
admin
=
setup
()
Model1
,
Model2
=
create_models
(
db
)
# fill DB with values
Model1
(
'test1_val_1'
,
'test2_val_1'
)
.
save
()
Model1
(
'test1_val_2'
,
'test2_val_2'
)
.
save
()
Model1
(
'test1_val_3'
,
'test2_val_3'
)
.
save
()
Model1
(
'test1_val_4'
,
'test2_val_4'
)
.
save
()
Model1
(
None
,
'empty_obj'
)
.
save
()
Model2
(
'char_field_val_1'
,
None
,
None
)
.
save
()
Model2
(
'char_field_val_2'
,
None
,
None
)
.
save
()
Model2
(
'char_field_val_3'
,
5000
,
25.9
)
.
save
()
Model2
(
'char_field_val_4'
,
9000
,
75.5
)
.
save
()
Model1
(
'date_obj1'
,
date_field
=
date
(
2014
,
11
,
17
))
.
save
()
Model1
(
'date_obj2'
,
date_field
=
date
(
2013
,
10
,
16
))
.
save
()
Model1
(
'timeonly_obj1'
,
timeonly_field
=
time
(
11
,
10
,
9
))
.
save
()
Model1
(
'timeonly_obj2'
,
timeonly_field
=
time
(
10
,
9
,
8
))
.
save
()
Model1
(
'datetime_obj1'
,
datetime_field
=
datetime
(
2014
,
4
,
3
,
1
,
9
,
0
))
.
save
()
Model1
(
'datetime_obj2'
,
datetime_field
=
datetime
(
2013
,
3
,
2
,
0
,
8
,
0
))
.
save
()
fill_db
(
Model1
,
Model2
)
# Test string filter
view
=
CustomModelView
(
Model1
,
column_filters
=
[
'test1'
])
...
...
flask_admin/tests/sqla/test_basic.py
View file @
eb37f32c
...
...
@@ -81,6 +81,39 @@ def create_models(db):
return
Model1
,
Model2
def
fill_db
(
db
,
Model1
,
Model2
):
model1_obj1
=
Model1
(
'test1_val_1'
,
'test2_val_1'
,
bool_field
=
True
)
model1_obj2
=
Model1
(
'test1_val_2'
,
'test2_val_2'
)
model1_obj3
=
Model1
(
'test1_val_3'
,
'test2_val_3'
)
model1_obj4
=
Model1
(
'test1_val_4'
,
'test2_val_4'
)
model2_obj1
=
Model2
(
'test2_val_1'
,
model1
=
model1_obj1
,
float_field
=
None
)
model2_obj2
=
Model2
(
'test2_val_2'
,
model1
=
model1_obj2
,
float_field
=
None
)
model2_obj3
=
Model2
(
'test2_val_3'
,
int_field
=
5000
,
float_field
=
25.9
)
model2_obj4
=
Model2
(
'test2_val_4'
,
int_field
=
9000
,
float_field
=
75.5
)
date_obj1
=
Model1
(
'date_obj1'
,
date_field
=
date
(
2014
,
11
,
17
))
date_obj2
=
Model1
(
'date_obj2'
,
date_field
=
date
(
2013
,
10
,
16
))
timeonly_obj1
=
Model1
(
'timeonly_obj1'
,
time_field
=
time
(
11
,
10
,
9
))
timeonly_obj2
=
Model1
(
'timeonly_obj2'
,
time_field
=
time
(
10
,
9
,
8
))
datetime_obj1
=
Model1
(
'datetime_obj1'
,
datetime_field
=
datetime
(
2014
,
4
,
3
,
1
,
9
,
0
))
datetime_obj2
=
Model1
(
'datetime_obj2'
,
datetime_field
=
datetime
(
2013
,
3
,
2
,
0
,
8
,
0
))
enum_obj1
=
Model1
(
'enum_obj1'
,
enum_field
=
"model1_v1"
)
enum_obj2
=
Model1
(
'enum_obj2'
,
enum_field
=
"model1_v2"
)
empty_obj
=
Model1
(
test2
=
"empty_obj"
)
db
.
session
.
add_all
([
model1_obj1
,
model1_obj2
,
model1_obj3
,
model1_obj4
,
model2_obj1
,
model2_obj2
,
model2_obj3
,
model2_obj4
,
date_obj1
,
timeonly_obj1
,
datetime_obj1
,
date_obj2
,
timeonly_obj2
,
datetime_obj2
,
enum_obj1
,
enum_obj2
,
empty_obj
])
db
.
session
.
commit
()
def
test_model
():
app
,
db
,
admin
=
setup
()
Model1
,
Model2
=
create_models
(
db
)
...
...
@@ -286,6 +319,56 @@ def test_complex_searchable_list_missing_children():
ok_
(
'magic string'
in
data
)
def
test_column_editable_list
():
app
,
db
,
admin
=
setup
()
Model1
,
Model2
=
create_models
(
db
)
view
=
CustomModelView
(
Model1
,
db
.
session
,
column_editable_list
=
[
'test1'
,
'enum_field'
])
admin
.
add_view
(
view
)
fill_db
(
db
,
Model1
,
Model2
)
client
=
app
.
test_client
()
# Test in-line edit field rendering
rv
=
client
.
get
(
'/admin/model1/'
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'data-role="x-editable"'
in
data
)
# Form - Test basic in-line edit functionality
rv
=
client
.
post
(
'/admin/model1/'
,
data
=
{
'test1-1'
:
'change-success-1'
,
})
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'Record was successfully saved.'
==
data
)
# ensure the value has changed
rv
=
client
.
get
(
'/admin/model1/'
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'change-success-1'
in
data
)
# Test errors
rv
=
client
.
post
(
'/admin/model1/'
,
data
=
{
'enum_field-1'
:
'problematic-input'
,
})
eq_
(
rv
.
status_code
,
500
)
view
=
CustomModelView
(
Model2
,
db
.
session
,
column_editable_list
=
[
'model1'
])
admin
.
add_view
(
view
)
# Test in-line editing for relations
rv
=
client
.
post
(
'/admin/model2/'
,
data
=
{
'model1-1'
:
'3'
,
})
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'Record was successfully saved.'
==
data
)
def
test_column_filters
():
app
,
db
,
admin
=
setup
()
...
...
@@ -393,37 +476,7 @@ def test_column_filters():
eq_
(
list
(
view
.
_filter_groups
.
keys
()),
[
u'Test Filter #1'
,
u'Test Filter #2'
])
# Fill DB
model1_obj1
=
Model1
(
'test1_val_1'
,
'test2_val_1'
,
bool_field
=
True
)
model1_obj2
=
Model1
(
'test1_val_2'
,
'test2_val_2'
)
model1_obj3
=
Model1
(
'test1_val_3'
,
'test2_val_3'
)
model1_obj4
=
Model1
(
'test1_val_4'
,
'test2_val_4'
)
model2_obj1
=
Model2
(
'test2_val_1'
,
model1
=
model1_obj1
,
float_field
=
None
)
model2_obj2
=
Model2
(
'test2_val_2'
,
model1
=
model1_obj2
,
float_field
=
None
)
model2_obj3
=
Model2
(
'test2_val_3'
,
int_field
=
5000
,
float_field
=
25.9
)
model2_obj4
=
Model2
(
'test2_val_4'
,
int_field
=
9000
,
float_field
=
75.5
)
date_obj1
=
Model1
(
'date_obj1'
,
date_field
=
date
(
2014
,
11
,
17
))
date_obj2
=
Model1
(
'date_obj2'
,
date_field
=
date
(
2013
,
10
,
16
))
timeonly_obj1
=
Model1
(
'timeonly_obj1'
,
time_field
=
time
(
11
,
10
,
9
))
timeonly_obj2
=
Model1
(
'timeonly_obj2'
,
time_field
=
time
(
10
,
9
,
8
))
datetime_obj1
=
Model1
(
'datetime_obj1'
,
datetime_field
=
datetime
(
2014
,
4
,
3
,
1
,
9
,
0
))
datetime_obj2
=
Model1
(
'datetime_obj2'
,
datetime_field
=
datetime
(
2013
,
3
,
2
,
0
,
8
,
0
))
enum_obj1
=
Model1
(
'enum_obj1'
,
enum_field
=
"model1_v1"
)
enum_obj2
=
Model1
(
'enum_obj2'
,
enum_field
=
"model1_v2"
)
empty_obj
=
Model1
(
test2
=
"empty_obj"
)
db
.
session
.
add_all
([
model1_obj1
,
model1_obj2
,
model1_obj3
,
model1_obj4
,
model2_obj1
,
model2_obj2
,
model2_obj3
,
model2_obj4
,
date_obj1
,
timeonly_obj1
,
datetime_obj1
,
date_obj2
,
timeonly_obj2
,
datetime_obj2
,
enum_obj1
,
enum_obj2
,
empty_obj
])
db
.
session
.
commit
()
fill_db
(
db
,
Model1
,
Model2
)
client
=
app
.
test_client
()
...
...
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