使用Flask-Admin

时间:2016-05-11 19:38:08

标签: python flask flask-admin

我正在尝试让fileadmin上传多个文件,但无法弄清楚如何做到这一点。

目前在以下参考中,我一次只能上传一个文件。

https://github.com/flask-admin/flask-admin/blob/master/examples/file/app.py
(新文件链接:https://github.com/mrjoes/flask-admin/blob/master/examples/file/app.py

我尝试将html模板更新为multiple="",但这并没有帮助上传多个文件。

进一步研究这个我认为这个html文件需要有multiple=""

  

Python27 \ LIB \站点包\ flask_admin \模板\ bootstrap3 \ adminC:\ Python27 \ LIB \站点包\ flask_admin \模板\ bootstrap3 \管理员\ lib.html

虽然我不确定在没有实际覆盖源文件的情况下添加此标记的位置/方式。

2 个答案:

答案 0 :(得分:4)

您应该按照以下方式自定义ImageUploadInputImageUploadField

import ast
from PIL import Image
from wtforms.widgets import html_params, HTMLString
from wtforms.utils import unset_value
from flask_admin.helpers import get_url
from flask_admin.form.upload import ImageUploadField
from flask_admin._compat import string_types, urljoin

class MultipleImageUploadInput(object):
    empty_template = "<input %(file)s multiple>"

    # display multiple images in edit view of flask-admin
    data_template = ("<div class='image-thumbnail'>"
                     "   %(images)s"
                     "</div>"
                     "<input %(file)s multiple>")

    def __call__(self, field, **kwargs):

        kwargs.setdefault("id", field.id)
        kwargs.setdefault("name", field.name)

        args = {
            "file": html_params(type="file", **kwargs),
        }

        if field.data and isinstance(field.data, string_types):

            attributes = self.get_attributes(field)

            args["images"] = "&emsp;".join(["<img src='{}' /><input type='checkbox' name='{}-delete'>Delete</input>"
                                            .format(src, filename) for src, filename in attributes])

            template = self.data_template

        else:
            template = self.empty_template

        return HTMLString(template % args)

    def get_attributes(self, field):

        for item in ast.literal_eval(field.data):

            filename = item

            if field.thumbnail_size:
                filename = field.thumbnail_size(filename)

            if field.url_relative_path:
                filename = urljoin(field.url_relative_path, filename)

            yield get_url(field.endpoint, filename=filename), item

class MultipleImageUploadField(ImageUploadField):

    widget = MultipleImageUploadInput()

    def process(self, formdata, data=unset_value):

        self.formdata = formdata  # get the formdata to delete images
        return super(MultipleImageUploadField, self).process(formdata, data)

    def process_formdata(self, valuelist):

        self.data = list()

        for value in valuelist:
            if self._is_uploaded_file(value):
                self.data.append(value)

    def populate_obj(self, obj, name):

        field = getattr(obj, name, None)

        if field:

            filenames = ast.literal_eval(field)

            for filename in filenames[:]:
                if filename + "-delete" in self.formdata:
                    self._delete_file(filename)
                    filenames.remove(filename)
        else:
            filenames = list()

        for data in self.data:
            if self._is_uploaded_file(data):

                self.image = Image.open(data)

                filename = self.generate_name(obj, data)
                filename = self._save_file(data, filename)

                data.filename = filename

                filenames.append(filename)

        setattr(obj, name, str(filenames))

之后,您可以将它们用作flask-admin

中的图像上传示例
class ModelHasMultipleImages(db.Model):

    id = db.Column(db.Integer(), primary_key=1)

    # len of str representation of filename lists may exceed the len of field

    image = db.Column(db.String(128))  

class ModelViewHasMultipleImages(ModelView):

    def _list_thumbnail(view, context, model, name):

        if not model.image:
            return ''

        def gen_img(filename):
            return '<img src="{}">'.format(url_for('static', 
                   filename="images/custom/" + form.thumbgen_filename(image)))

        return Markup("<br />".join([gen_img(image) for image in ast.literal_eval(model.image)]))

    column_formatters = {'image': _list_thumbnail}

    form_extra_fields = {'image': MultipleImageUploadField("Images",
                                  base_path="app/static/images/custom",
                                  url_relative_path="images/custom/",
                                  thumbnail_size=(400, 300, 1))}

ModelHasMultipleImages的图像存储str表示文件名列表。

答案 1 :(得分:0)

Dropzone是执行此操作的最佳方法

使用

下载
pip install flask flask-uploads flask-dropzone

Python app.py应该看起来像这样

# app.py

from flask import Flask, render_template
from flask_dropzone import Dropzone
from flask_uploads import UploadSet, configure_uploads, IMAGES, patch_request_class

import os

app = Flask(__name__)
dropzone = Dropzone(app)

# Dropzone settings
app.config['DROPZONE_UPLOAD_MULTIPLE'] = True
app.config['DROPZONE_ALLOWED_FILE_CUSTOM'] = True
app.config['DROPZONE_ALLOWED_FILE_TYPE'] = 'image/*'
app.config['DROPZONE_REDIRECT_VIEW'] = 'results'

# Uploads settings
app.config['UPLOADED_PHOTOS_DEST'] = os.getcwd() + '/uploads'

photos = UploadSet('photos', IMAGES)
configure_uploads(app, photos)
patch_request_class(app)  # set maximum file size, default is 16MB

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/results')
def results():
    return render_template('results.html')

result.html如下

# templates/results.html

<h1>Hello Results Page!</h1>
<a href="{{ url_for('index') }}">Back</a><p>

<ul>
{% for file_url in file_urls %}
    <li><img style="height: 150px" src="{{ file_url }}"></li>
{% endfor %}
</ul>

index.html看起来像这样

# templates/index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Flask App</title>
        {{ dropzone.load() }}
        {{ dropzone.style('border: 2px dashed #0087F7; margin: 10%; min-height: 400px;') }}
    </head>
    <body>
        <h1>Hello from Flask!</h1>
        {{ dropzone.create(action_view='index') }}
    </body>
</html>