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
8f775371
Commit
8f775371
authored
Feb 18, 2016
by
Paul Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1203 from iurisilvio/export_xlsx
Tablib export
parents
baf191d1
7cf4f4f9
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
127 additions
and
21 deletions
+127
-21
base.py
flask_admin/model/base.py
+83
-15
layout.html
flask_admin/templates/bootstrap2/admin/model/layout.html
+21
-0
list.html
flask_admin/templates/bootstrap2/admin/model/list.html
+1
-3
layout.html
flask_admin/templates/bootstrap3/admin/model/layout.html
+21
-0
list.html
flask_admin/templates/bootstrap3/admin/model/list.html
+1
-3
No files found.
flask_admin/model/base.py
View file @
8f775371
import
warnings
import
warnings
import
re
import
re
import
csv
import
csv
import
mimetypes
import
time
import
time
from
werkzeug
import
secure_filename
from
werkzeug
import
secure_filename
...
@@ -8,6 +9,10 @@ from werkzeug import secure_filename
...
@@ -8,6 +9,10 @@ from werkzeug import secure_filename
from
flask
import
(
request
,
redirect
,
flash
,
abort
,
json
,
Response
,
from
flask
import
(
request
,
redirect
,
flash
,
abort
,
json
,
Response
,
get_flashed_messages
,
stream_with_context
)
get_flashed_messages
,
stream_with_context
)
from
jinja2
import
contextfunction
from
jinja2
import
contextfunction
try
:
import
tablib
except
ImportError
:
tablib
=
None
from
wtforms.fields
import
HiddenField
from
wtforms.fields
import
HiddenField
from
wtforms.fields.core
import
UnboundField
from
wtforms.fields.core
import
UnboundField
from
wtforms.validators
import
ValidationError
,
InputRequired
from
wtforms.validators
import
ValidationError
,
InputRequired
...
@@ -683,6 +688,15 @@ class BaseModelView(BaseView, ActionsMixin):
...
@@ -683,6 +688,15 @@ class BaseModelView(BaseView, ActionsMixin):
Unlimited by default. Uses `page_size` if set to `None`.
Unlimited by default. Uses `page_size` if set to `None`.
"""
"""
export_types
=
[
'csv'
]
"""
A list of available export filetypes. `csv` only is default, but any
filetypes supported by tablib can be used.
Check tablib for https://github.com/kennethreitz/tablib/bloab/master/README.rst
for supported types.
"""
# Various settings
# Various settings
page_size
=
20
page_size
=
20
"""
"""
...
@@ -1696,12 +1710,13 @@ class BaseModelView(BaseView, ActionsMixin):
...
@@ -1696,12 +1710,13 @@ class BaseModelView(BaseView, ActionsMixin):
self
.
column_type_formatters_export
,
self
.
column_type_formatters_export
,
)
)
def
get_export_name
(
self
):
def
get_export_name
(
self
,
export_type
=
'csv'
):
"""
"""
:return: The exported csv file name.
:return: The exported csv file name.
"""
"""
filename
=
'
%
s_
%
s.csv'
%
(
self
.
name
,
filename
=
'
%
s_
%
s.
%
s'
%
(
self
.
name
,
time
.
strftime
(
"
%
Y-
%
m-
%
d_
%
H-
%
M-
%
S"
))
time
.
strftime
(
"
%
Y-
%
m-
%
d_
%
H-
%
M-
%
S"
),
export_type
)
return
filename
return
filename
# AJAX references
# AJAX references
...
@@ -2001,17 +2016,7 @@ class BaseModelView(BaseView, ActionsMixin):
...
@@ -2001,17 +2016,7 @@ class BaseModelView(BaseView, ActionsMixin):
"""
"""
return
self
.
handle_action
()
return
self
.
handle_action
()
@
expose
(
'/export/csv/'
)
def
_export_data
(
self
):
def
export_csv
(
self
):
"""
Export a CSV of records.
"""
return_url
=
get_redirect_target
()
or
self
.
get_url
(
'.index_view'
)
if
not
self
.
can_export
:
flash
(
gettext
(
'Permission denied.'
))
return
redirect
(
return_url
)
# Macros in column_formatters are not supported.
# Macros in column_formatters are not supported.
# Macros will have a function name 'inner'
# Macros will have a function name 'inner'
# This causes non-macro functions named 'inner' not work.
# This causes non-macro functions named 'inner' not work.
...
@@ -2040,6 +2045,27 @@ class BaseModelView(BaseView, ActionsMixin):
...
@@ -2040,6 +2045,27 @@ class BaseModelView(BaseView, ActionsMixin):
view_args
.
search
,
view_args
.
filters
,
view_args
.
search
,
view_args
.
filters
,
page_size
=
self
.
export_max_rows
)
page_size
=
self
.
export_max_rows
)
return
count
,
data
@
expose
(
'/export/<export_type>/'
)
def
export
(
self
,
export_type
):
return_url
=
get_redirect_target
()
or
self
.
get_url
(
'.index_view'
)
if
not
self
.
can_export
or
(
export_type
not
in
self
.
export_types
):
flash
(
gettext
(
'Permission denied.'
))
return
redirect
(
return_url
)
if
export_type
==
'csv'
:
return
self
.
_export_csv
(
return_url
)
else
:
return
self
.
_export_tablib
(
export_type
,
return_url
)
def
_export_csv
(
self
,
return_url
):
"""
Export a CSV of records as a stream.
"""
count
,
data
=
self
.
_export_data
()
# https://docs.djangoproject.com/en/1.8/howto/outputting-csv/
# https://docs.djangoproject.com/en/1.8/howto/outputting-csv/
class
Echo
(
object
):
class
Echo
(
object
):
"""
"""
...
@@ -2065,7 +2091,7 @@ class BaseModelView(BaseView, ActionsMixin):
...
@@ -2065,7 +2091,7 @@ class BaseModelView(BaseView, ActionsMixin):
for
c
in
self
.
_export_columns
]
for
c
in
self
.
_export_columns
]
yield
writer
.
writerow
(
vals
)
yield
writer
.
writerow
(
vals
)
filename
=
self
.
get_export_name
()
filename
=
self
.
get_export_name
(
export_type
=
'csv'
)
disposition
=
'attachment;filename=
%
s'
%
(
secure_filename
(
filename
),)
disposition
=
'attachment;filename=
%
s'
%
(
secure_filename
(
filename
),)
...
@@ -2075,6 +2101,48 @@ class BaseModelView(BaseView, ActionsMixin):
...
@@ -2075,6 +2101,48 @@ class BaseModelView(BaseView, ActionsMixin):
mimetype
=
'text/csv'
mimetype
=
'text/csv'
)
)
def
_export_tablib
(
self
,
export_type
,
return_url
):
"""
Exports a variety of formats using the tablib library.
"""
if
tablib
is
None
:
flash
(
gettext
(
'Tablib dependency not installed.'
))
return
redirect
(
return_url
)
filename
=
self
.
get_export_name
(
export_type
)
disposition
=
'attachment;filename=
%
s'
%
(
secure_filename
(
filename
),)
mimetype
,
encoding
=
mimetypes
.
guess_type
(
filename
)
if
not
mimetype
:
mimetype
=
'application/octet-stream'
if
encoding
:
mimetype
=
'
%
s; charset=
%
s'
%
(
mimetype
,
encoding
)
ds
=
tablib
.
Dataset
(
headers
=
[
c
[
1
]
for
c
in
self
.
_export_columns
])
count
,
data
=
self
.
_export_data
()
for
row
in
data
:
vals
=
[
self
.
get_export_value
(
row
,
c
[
0
])
for
c
in
self
.
_export_columns
]
ds
.
append
(
vals
)
try
:
try
:
response_data
=
ds
.
export
(
format
=
export_type
)
except
AttributeError
:
response_data
=
getattr
(
ds
,
export_type
)
except
(
AttributeError
,
tablib
.
UnsupportedFormat
):
flash
(
gettext
(
'Export type "
%(type)
s not supported.'
,
type
=
export_type
))
return
redirect
(
return_url
)
return
Response
(
response_data
,
headers
=
{
'Content-Disposition'
:
disposition
},
mimetype
=
mimetype
,
)
@
expose
(
'/ajax/lookup/'
)
@
expose
(
'/ajax/lookup/'
)
def
ajax_lookup
(
self
):
def
ajax_lookup
(
self
):
name
=
request
.
args
.
get
(
'name'
)
name
=
request
.
args
.
get
(
'name'
)
...
...
flask_admin/templates/bootstrap2/admin/model/layout.html
View file @
8f775371
...
@@ -11,6 +11,27 @@
...
@@ -11,6 +11,27 @@
</ul>
</ul>
{% endmacro %}
{% endmacro %}
{% macro export_options(btn_class='dropdown-toggle') %}
{% if admin_view.export_types|length > 1 %}
<li
class=
"dropdown"
>
<a
class=
"{{ btn_class }}"
data-toggle=
"dropdown"
href=
"javascript:void(0)"
>
{{ _gettext('Export') }}
<b
class=
"caret"
></b>
</a>
<ul
class=
"dropdown-menu field-filters"
>
{% for export_type in admin_view.export_types %}
<li>
<a
href=
"{{ get_url('.export', export_type=export_type, **request.args) }}"
title=
"{{ _gettext('Export') }}"
>
{{ _gettext('Export') + ' ' + export_type|upper }}
</a>
</li>
{% endfor %}
</ul>
</li>
{% else %}
<li>
<a
href=
"{{ get_url('.export', export_type=admin_view.export_types[0], **request.args) }}"
title=
"{{ _gettext('Export') }}"
>
{{ _gettext('Export') }}
</a>
</li>
{% endif %}
{% endmacro %}
{% macro filter_form() %}
{% macro filter_form() %}
<form
id=
"filter_form"
method=
"GET"
action=
"{{ return_url }}"
>
<form
id=
"filter_form"
method=
"GET"
action=
"{{ return_url }}"
>
<div
class=
"pull-right"
>
<div
class=
"pull-right"
>
...
...
flask_admin/templates/bootstrap2/admin/model/list.html
View file @
8f775371
...
@@ -27,9 +27,7 @@
...
@@ -27,9 +27,7 @@
{% endif %}
{% endif %}
{% if admin_view.can_export %}
{% if admin_view.can_export %}
<li>
{{ model_layout.export_options() }}
<a
href=
"{{ get_url('.export_csv', **request.args) }}"
title=
"{{ _gettext('Export') }}"
>
{{ _gettext('Export') }}
</a>
</li>
{% endif %}
{% endif %}
{% block model_menu_bar_before_filters %}{% endblock %}
{% block model_menu_bar_before_filters %}{% endblock %}
...
...
flask_admin/templates/bootstrap3/admin/model/layout.html
View file @
8f775371
...
@@ -11,6 +11,27 @@
...
@@ -11,6 +11,27 @@
</ul>
</ul>
{% endmacro %}
{% endmacro %}
{% macro export_options(btn_class='dropdown-toggle') %}
{% if admin_view.export_types|length > 1 %}
<li
class=
"dropdown"
>
<a
class=
"{{ btn_class }}"
data-toggle=
"dropdown"
href=
"javascript:void(0)"
>
{{ _gettext('Export') }}
<b
class=
"caret"
></b>
</a>
<ul
class=
"dropdown-menu field-filters"
>
{% for export_type in admin_view.export_types %}
<li>
<a
href=
"{{ get_url('.export', export_type=export_type, **request.args) }}"
title=
"{{ _gettext('Export') }}"
>
{{ _gettext('Export') + ' ' + export_type|upper }}
</a>
</li>
{% endfor %}
</ul>
</li>
{% else %}
<li>
<a
href=
"{{ get_url('.export', export_type=admin_view.export_types[0], **request.args) }}"
title=
"{{ _gettext('Export') }}"
>
{{ _gettext('Export') }}
</a>
</li>
{% endif %}
{% endmacro %}
{% macro filter_form() %}
{% macro filter_form() %}
<form
id=
"filter_form"
method=
"GET"
action=
"{{ return_url }}"
>
<form
id=
"filter_form"
method=
"GET"
action=
"{{ return_url }}"
>
<div
class=
"pull-right"
>
<div
class=
"pull-right"
>
...
...
flask_admin/templates/bootstrap3/admin/model/list.html
View file @
8f775371
...
@@ -27,9 +27,7 @@
...
@@ -27,9 +27,7 @@
{% endif %}
{% endif %}
{% if admin_view.can_export %}
{% if admin_view.can_export %}
<li>
{{ model_layout.export_options() }}
<a
href=
"{{ get_url('.export_csv', **request.args) }}"
title=
"{{ _gettext('Export') }}"
>
{{ _gettext('Export') }}
</a>
</li>
{% endif %}
{% endif %}
{% block model_menu_bar_before_filters %}{% endblock %}
{% block model_menu_bar_before_filters %}{% endblock %}
...
...
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