Export and import for MongoEngine model in Flask-Admin
Another tip for Flask-Admin. The task’s requirements are:
- possibility to choose some model’s objects and download them in JSON
- possibility to upload them back
There is a ModelView property can_export, it adds an action to export in CSV or another format supported by tablib, but it does not allow to select records and there is no import. So for my task it’s not a solution.
The export is easy to do with an action decorathor.
class MyModel(Document)
name = StringField(max_lengt=255)
data = DictField()
date = DateTimeField(default=datetime.utcnow)
class MyView(ModelView):
@action('export', 'Export')
def action_export(self, ids):
try:
items = list(MyModel.objects(id__in=ids))
if items:
items = [
{'name': item.name,'data': item.data}
for item in items
]
return (
json.dumps(items, indent=4),
200,
{
'Content-Type': 'application/json',
'Pragma': 'no-cache',
'Cache-Control': 'no-cache, no-store, must-revalidate',
'Expires': '0',
'Content-Disposition': 'attachment; filename="mymodel.json"'
}
)
return ''
except Exception as e:
if not self.handle_view_exception(e):
raise
flash('Failed to export: {}'.format(str(e)), 'error')
The import is a little more complex, it requires to customize the template.
In this example I put it at the bottom of the list page admin/mymodel_list.html
.
{% extends 'admin/model/list.html' %}
{% block body %}
{{ super() }}
<form action="{{ url_for('admin_mymodel.import_json') }}"
method="POST"
enctype="multipart/form-data"
class="admin-form form-inline">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<div class="form-group">
<input type="file" name="file" class="form-control"/>
<button type="submit" class="btn btn-default">Import</button>
</div>
</form>
{% endblock %}
And added a view with @expose
decorathor to proccess this form.
class MyView(ModelView):
list_template = 'admin/mymodel_list.html'
@expose('/import', methods=['POST'])
def import_json(self):
redirect_response = redirect(url_for('admin_mymodel.index_view'))
if 'file' not in request.files:
flash('No file part', 'error')
return redirect_response
uploaded_file = request.files['file']
if uploaded_file.filename == '':
flash('No selected file', 'error')
return redirect_response
if uploaded_file:
try:
items = json.loads(uploaded_file.read().decode('utf-8'))
except (json.JSONDecodeError, TypeError, UnicodeDecodeError) as e:
flash('Can not read json from the file. {}'.format(e), 'error')
return redirect_response
for item in items:
MyModel(**item).save()
return redirect_response
To add view to admin:
adm = Admin()
adm.add_view(MyView(MyModel, endpoint='admin_mymodel'))