In my last post Checking out: Flask-Admin extension I gave a
short introduction to the Flask-Admin extension. I also built a small example to show
how easy it is to get a basic admin interface for your data. But how does Flask-Admin
work if we have more advanced requirements? For example what if we want to provide an
image for each user? In this case we will have to expand our recent example by an
Image model.
class Image(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128))
path = db.Column(db.String, unique=True)
def __repr__(self):
return self.name
To administer the new Image model we need to create a ModelView for it. This time it
won' t be enough to just use the ModelView provided by Flask-admin. We want to be able
to upload a new image via an upload button and get a nice preview of our image. We need
to create our own ImageView class here. I basically used the Flask-Admin example
[Files, images & custom forms](Files, images & custom forms) here.
basedir = os.path.abspath(os.path.dirname(__file__))
file_path = os.path.join(basedir, 'files')
Alright, that' s it. You can find the whole example on https://github.com/MrLeeh/flask-admin-examples-images.
class ImageView(ModelView):
def _list_thumbnail(view, context, model, name):
if not model.path:
return ''
return Markup(
'<img src="%s">' %
url_for('static',
filename=form.thumbgen_filename(model.path))
)
column_formatters = {
'path': _list_thumbnail
}
form_extra_fields = {
'path': form.ImageUploadField(
'Image', base_path=file_path, thumbnail_size=(100, 100, True))
}
admin.add_view(ImageView(Image, db.session))
That's great, we can upload images. Now we want to use them to give our users a face.
For this we need to modify our User model and create a UserView class.
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True)
image_id = db.Column(db.Integer, db.ForeignKey('image.id'))
image = db.relationship('Image')
class UserView(ModelView):
def _list_thumbnail(view, context, model, name):
if not model.image or not model.image.path:
return ''
return Markup(
'<img src="%s">' %
url_for('static',
filename=form.thumbgen_filename(model.image.path))
)
column_formatters = {
'image': _list_thumbnail
}
admin.add_view(UserView(User, db.session))
Now this will show the image for each user in the user list. That is very nice. Also
when we edit a user we magically get a nice Select2 field that let's us choose our user
image. Only we don't get a preview of this image. To include a preview we need to
provide our own edit template edit_user.html:
{% extends 'admin/model/edit.html' %}
{% block head %}
{{ super() }}
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
<script>
$(document).ready(function() {
$('select').on('change', function(event) {
var img_id = $(this).val();
$.getJSON(
'{{ url_for('_get_image_url') }}',
{img_id: img_id},
function(data) {
if (data.status == 'ok') {
$('img').prop('src', {{ url_for('static', filename='') }} + data.img_path);
}
else {
}
});
});
});
</script>
{% endblock %}
{% block edit_form %}
{{ super() }}
<img src="{{ url_for('static', filename=model.image.path) }}" style="max-height:200px;">
{% endblock %}
We tell Flask-Admin to use this template by adding the following line to our `UserView` class.
```python
edit_template = 'edit_user.html'
Now what is it doing. Actually we keep the default template but only add an image tag at
the bottom. We use jQuery to listen to the change event of our image select field. If
it is changed we will send an ajax call to our server, ask for the image path of the
currently selected image and load it in our img element.
Of course for this to work we still need to implement the endpoint get_image_url in
our application.
@app.route('/_image-url')
def _get_image_url():
img_id = request.args.get('img_id')
img = Image.query.get(img_id)
if img is None:
response = jsonify(status='not found')
return response
return jsonify(img_path=img.path, status='ok')
Alright, that' s it. Now you can choose and preview the images of your user. You can find the whole example on https://github.com/MrLeeh/flask-admin-examples-images.