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
87f8a188
Commit
87f8a188
authored
Jul 02, 2019
by
P.J. Janse van Rensburg
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into bootstrap4
parents
e9f97ba1
e9ef3bf6
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
83 additions
and
9 deletions
+83
-9
changelog.rst
doc/changelog.rst
+1
-0
introduction.rst
doc/introduction.rst
+4
-0
ajax.py
flask_admin/contrib/sqla/ajax.py
+5
-2
base.py
flask_admin/model/base.py
+20
-7
layout.html
flask_admin/templates/bootstrap2/admin/model/layout.html
+6
-0
layout.html
flask_admin/templates/bootstrap3/admin/model/layout.html
+6
-0
test_basic.py
flask_admin/tests/sqla/test_basic.py
+41
-0
No files found.
doc/changelog.rst
View file @
87f8a188
...
@@ -7,6 +7,7 @@ Next release
...
@@ -7,6 +7,7 @@ Next release
* Fix display of inline x-editable boolean fields on list view
* Fix display of inline x-editable boolean fields on list view
* Add support for several SQLAlchemy-Utils data types
* Add support for several SQLAlchemy-Utils data types
* Support searching on SQLAlchemy hybrid properties
* Support searching on SQLAlchemy hybrid properties
* Extra URL paramaters are now propagated to the next page when searching / filtering
* Add enum34 dependency when running on legacy Python version
* Add enum34 dependency when running on legacy Python version
* Update Mapbox API v1 URL format
* Update Mapbox API v1 URL format
* Update jQuery and moment dependencies in templates
* Update jQuery and moment dependencies in templates
...
...
doc/introduction.rst
View file @
87f8a188
...
@@ -405,6 +405,10 @@ Now, to make your view classes use this template, set the appropriate class prop
...
@@ -405,6 +405,10 @@ Now, to make your view classes use this template, set the appropriate class prop
edit_template = 'microblog_edit.html'
edit_template = 'microblog_edit.html'
# create_template = 'microblog_create.html'
# create_template = 'microblog_create.html'
# list_template = 'microblog_list.html'
# list_template = 'microblog_list.html'
# details_template = 'microblog_details.html'
# edit_modal_template = 'microblog_edit_modal.html'
# create_modal_template = 'microblog_create_modal.html'
# details_modal_template = 'microblog_details_modal.html'
If you want to use your own base template, then pass the name of the template to
If you want to use your own base template, then pass the name of the template to
the admin constructor during initialization::
the admin constructor during initialization::
...
...
flask_admin/contrib/sqla/ajax.py
View file @
87f8a188
...
@@ -58,13 +58,16 @@ class QueryAjaxModelLoader(AjaxModelLoader):
...
@@ -58,13 +58,16 @@ class QueryAjaxModelLoader(AjaxModelLoader):
return
getattr
(
model
,
self
.
pk
),
as_unicode
(
model
)
return
getattr
(
model
,
self
.
pk
),
as_unicode
(
model
)
def
get_query
(
self
):
return
self
.
session
.
query
(
self
.
model
)
def
get_one
(
self
,
pk
):
def
get_one
(
self
,
pk
):
# prevent autoflush from occuring during populate_obj
# prevent autoflush from occuring during populate_obj
with
self
.
session
.
no_autoflush
:
with
self
.
session
.
no_autoflush
:
return
self
.
session
.
query
(
self
.
model
)
.
get
(
pk
)
return
self
.
get_query
(
)
.
get
(
pk
)
def
get_list
(
self
,
term
,
offset
=
0
,
limit
=
DEFAULT_PAGE_SIZE
):
def
get_list
(
self
,
term
,
offset
=
0
,
limit
=
DEFAULT_PAGE_SIZE
):
query
=
self
.
session
.
query
(
self
.
model
)
query
=
self
.
get_query
(
)
filters
=
(
cast
(
field
,
String
)
.
ilike
(
u'
%%%
s
%%
'
%
term
)
for
field
in
self
.
_cached_fields
)
filters
=
(
cast
(
field
,
String
)
.
ilike
(
u'
%%%
s
%%
'
%
term
)
for
field
in
self
.
_cached_fields
)
query
=
query
.
filter
(
or_
(
*
filters
))
query
=
query
.
filter
(
or_
(
*
filters
))
...
...
flask_admin/model/base.py
View file @
87f8a188
...
@@ -1701,29 +1701,39 @@ class BaseModelView(BaseView, ActionsMixin):
...
@@ -1701,29 +1701,39 @@ class BaseModelView(BaseView, ActionsMixin):
def
get_empty_list_message
(
self
):
def
get_empty_list_message
(
self
):
return
gettext
(
'There are no items in the table.'
)
return
gettext
(
'There are no items in the table.'
)
def
get_invalid_value_msg
(
self
,
value
,
filter
):
"""
Returns message, which should be printed in case of failed validation.
:param value: Invalid value
:param filter: Filter
:return: string
"""
return
gettext
(
'Invalid Filter Value:
%(value)
s'
,
value
=
value
)
# URL generation helpers
# URL generation helpers
def
_get_list_filter_args
(
self
):
def
_get_list_filter_args
(
self
):
if
self
.
_filters
:
if
self
.
_filters
:
filters
=
[]
filters
=
[]
for
n
in
request
.
args
:
for
arg
in
request
.
args
:
if
not
n
.
startswith
(
'flt'
):
if
not
arg
.
startswith
(
'flt'
):
continue
continue
if
'_'
not
in
n
:
if
'_'
not
in
arg
:
continue
continue
pos
,
key
=
n
[
3
:]
.
split
(
'_'
,
1
)
pos
,
key
=
arg
[
3
:]
.
split
(
'_'
,
1
)
if
key
in
self
.
_filter_args
:
if
key
in
self
.
_filter_args
:
idx
,
flt
=
self
.
_filter_args
[
key
]
idx
,
flt
=
self
.
_filter_args
[
key
]
value
=
request
.
args
[
n
]
value
=
request
.
args
[
arg
]
if
flt
.
validate
(
value
):
if
flt
.
validate
(
value
):
filters
.
append
((
pos
,
(
idx
,
as_unicode
(
flt
.
name
),
value
)))
data
=
(
pos
,
(
idx
,
as_unicode
(
flt
.
name
),
value
))
filters
.
append
(
data
)
else
:
else
:
flash
(
gettext
(
'Invalid Filter Value:
%(value)
s'
,
value
=
value
),
'error'
)
flash
(
self
.
get_invalid_value_msg
(
value
,
flt
),
'error'
)
# Sort filters
# Sort filters
return
[
v
[
1
]
for
v
in
sorted
(
filters
,
key
=
lambda
n
:
n
[
0
])]
return
[
v
[
1
]
for
v
in
sorted
(
filters
,
key
=
lambda
n
:
n
[
0
])]
...
@@ -2054,6 +2064,9 @@ class BaseModelView(BaseView, ActionsMixin):
...
@@ -2054,6 +2064,9 @@ class BaseModelView(BaseView, ActionsMixin):
get_pk_value
=
self
.
get_pk_value
,
get_pk_value
=
self
.
get_pk_value
,
get_value
=
self
.
get_list_value
,
get_value
=
self
.
get_list_value
,
return_url
=
self
.
_get_list_url
(
view_args
),
return_url
=
self
.
_get_list_url
(
view_args
),
# Extras
extra_args
=
view_args
.
extra_args
,
)
)
@
expose
(
'/new/'
,
methods
=
(
'GET'
,
'POST'
))
@
expose
(
'/new/'
,
methods
=
(
'GET'
,
'POST'
))
...
...
flask_admin/templates/bootstrap2/admin/model/layout.html
View file @
87f8a188
...
@@ -34,6 +34,9 @@
...
@@ -34,6 +34,9 @@
{% macro filter_form() %}
{% macro filter_form() %}
<form
id=
"filter_form"
method=
"GET"
action=
"{{ return_url }}"
>
<form
id=
"filter_form"
method=
"GET"
action=
"{{ return_url }}"
>
{% for arg_name, arg_value in extra_args.items() %}
<input
type=
"hidden"
name=
"{{ arg_name }}"
value=
"{{ arg_value }}"
>
{% endfor %}
{% if sort_column is not none %}
{% if sort_column is not none %}
<input
type=
"hidden"
name=
"sort"
value=
"{{ sort_column }}"
>
<input
type=
"hidden"
name=
"sort"
value=
"{{ sort_column }}"
>
{% endif %}
{% endif %}
...
@@ -63,6 +66,9 @@
...
@@ -63,6 +66,9 @@
{% for flt_name, flt_value in filter_args.items() %}
{% for flt_name, flt_value in filter_args.items() %}
<input
type=
"hidden"
name=
"{{ flt_name }}"
value=
"{{ flt_value }}"
>
<input
type=
"hidden"
name=
"{{ flt_name }}"
value=
"{{ flt_value }}"
>
{% endfor %}
{% endfor %}
{% for arg_name, arg_value in extra_args.items() %}
<input
type=
"hidden"
name=
"{{ arg_name }}"
value=
"{{ arg_value }}"
>
{% endfor %}
{% if page_size != default_page_size %}
{% if page_size != default_page_size %}
<input
type=
"hidden"
name=
"page_size"
value=
"{{ page_size }}"
>
<input
type=
"hidden"
name=
"page_size"
value=
"{{ page_size }}"
>
{% endif %}
{% endif %}
...
...
flask_admin/templates/bootstrap3/admin/model/layout.html
View file @
87f8a188
...
@@ -34,6 +34,9 @@
...
@@ -34,6 +34,9 @@
{% macro filter_form() %}
{% macro filter_form() %}
<form
id=
"filter_form"
method=
"GET"
action=
"{{ return_url }}"
>
<form
id=
"filter_form"
method=
"GET"
action=
"{{ return_url }}"
>
{% for arg_name, arg_value in extra_args.items() %}
<input
type=
"hidden"
name=
"{{ arg_name }}"
value=
"{{ arg_value }}"
>
{% endfor %}
{% if sort_column is not none %}
{% if sort_column is not none %}
<input
type=
"hidden"
name=
"sort"
value=
"{{ sort_column }}"
>
<input
type=
"hidden"
name=
"sort"
value=
"{{ sort_column }}"
>
{% endif %}
{% endif %}
...
@@ -63,6 +66,9 @@
...
@@ -63,6 +66,9 @@
{% for flt_name, flt_value in filter_args.items() %}
{% for flt_name, flt_value in filter_args.items() %}
<input
type=
"hidden"
name=
"{{ flt_name }}"
value=
"{{ flt_value }}"
>
<input
type=
"hidden"
name=
"{{ flt_name }}"
value=
"{{ flt_value }}"
>
{% endfor %}
{% endfor %}
{% for arg_name, arg_value in extra_args.items() %}
<input
type=
"hidden"
name=
"{{ arg_name }}"
value=
"{{ arg_value }}"
>
{% endfor %}
{% if page_size != default_page_size %}
{% if page_size != default_page_size %}
<input
type=
"hidden"
name=
"page_size"
value=
"{{ page_size }}"
>
<input
type=
"hidden"
name=
"page_size"
value=
"{{ page_size }}"
>
{% endif %}
{% endif %}
...
...
flask_admin/tests/sqla/test_basic.py
View file @
87f8a188
...
@@ -436,6 +436,47 @@ def test_column_searchable_list():
...
@@ -436,6 +436,47 @@ def test_column_searchable_list():
ok_
(
'model2-test'
in
data
)
ok_
(
'model2-test'
in
data
)
def
test_extra_args_search
():
app
,
db
,
admin
=
setup
()
Model1
,
Model2
=
create_models
(
db
)
view1
=
CustomModelView
(
Model1
,
db
.
session
,
column_searchable_list
=
[
'test1'
,
])
admin
.
add_view
(
view1
)
db
.
session
.
add
(
Model2
(
'model1-test'
,
))
db
.
session
.
commit
()
client
=
app
.
test_client
()
# check that extra args in the url are propagated as hidden fields in the search form
rv
=
client
.
get
(
'/admin/model1/?search=model1&foo=bar'
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'<input type="hidden" name="foo" value="bar">'
in
data
)
def
test_extra_args_filter
():
app
,
db
,
admin
=
setup
()
Model1
,
Model2
=
create_models
(
db
)
view2
=
CustomModelView
(
Model2
,
db
.
session
,
column_filters
=
[
'int_field'
,
])
admin
.
add_view
(
view2
)
db
.
session
.
add
(
Model2
(
'model2-test'
,
5000
))
db
.
session
.
commit
()
client
=
app
.
test_client
()
# check that extra args in the url are propagated as hidden fields in the form
rv
=
client
.
get
(
'/admin/model2/?flt1_0=5000&foo=bar'
)
data
=
rv
.
data
.
decode
(
'utf-8'
)
ok_
(
'<input type="hidden" name="foo" value="bar">'
in
data
)
def
test_complex_searchable_list
():
def
test_complex_searchable_list
():
app
,
db
,
admin
=
setup
()
app
,
db
,
admin
=
setup
()
...
...
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