flask-admin - 如何在pymongo后端使用ImageUploadField
我在用flask-admin和pymongo(不是mongoengine)数据库,遇到了使用新的flask-admin的ImageUploadField时的严重问题。
简单来说,我就是搞不定它。我花了两天时间尝试复制一些示例代码,这些示例在sqla上运行得很好。以下是我的管理员类定义:
from jinja2 import Markup
from flask_admin.contrib.pymongo import ModelView, filters
from flask_admin import form
from flask_admin.model import fields
from flask_admin.form.upload import ImageUploadField
from flask_admin.form import rules, widgets
import flask_wtf as wtf
from wtforms import validators as wtfv
from wtforms import widgets as wtfw
from wtforms import fields as wtff
class PhotoForm(wtf.Form):
label = wtff.TextField('Label')
file = ImageUploadField('Image', base_path=file_path, thumbnail_size=(100, 100, True))
def __init__(self, *args, **kwargs):
kwargs['csrf_enabled'] = True
super(PhotoForm, self).__init__(*args, **kwargs)
class EquipmentForm(wtf.Form):
photo = fields.InlineFieldList(fields.InlineFormField(PhotoForm))
class EquipmentViewRoot(ModelView):
def _list_thumbnail(view, context, model, name):
if not model['photo']:
return ''
return Markup('<img src="%s">' % url_for('static', filename=form.thumbgen_filename(model.path)))
can_create = True
column_list = ('photo')
column_formatters = {
'photo': _list_thumbnail
}
form = EquipmentForm
表单显示得没问题,但一点击保存按钮,如果选择了一个图片文件,就会出现错误提示,告诉我pymongo无法保存模型,因为它包含了一个二进制对象。
根据文档(还有源代码),ImageUploadField应该把图片保存在uploads目录下,并用文件名替换模型中的二进制对象。这在sqla中可以正常工作,但在pymongo中却不行。看起来没有任何东西在调用ImageUploadField类的populate_obj方法。
你觉得我哪里做错了呢?
1 个回答
3
明白了。ImageUploadField 的 populate_obj 方法在使用 pymongo 作为后端时没有效果,因为它是针对对象属性工作的,而 pymongo 使用的是普通的字典,而不是对象。
我通过简单地创建一个 ImageUploadField 的子类,并重写 populate_obj 方法,使其可以处理字典,来解决这个问题。
我创建了一个 utils.py 文件,里面包含了以下内容:
from flask_admin.form.upload import ImageUploadField as iuf
from werkzeug.datastructures import FileStorage
class ImageUploadField(iuf):
def __init__(self, *args, **kwargs):
super(ImageUploadField, self).__init__(*args, **kwargs)
def populate_obj(self, obj, name):
field = getattr(obj, name, None)
if field:
# If field should be deleted, clean it up
if self._should_delete:
self._delete_file(field)
setattr(obj, name, None)
return
if self.data and isinstance(self.data, FileStorage):
if field:
self._delete_file(field)
filename = self.generate_name(obj, self.data)
filename = self._save_file(self.data, filename)
# update filename of FileStorage to our validated name
self.data.filename = filename
obj[name] = filename # this is the patched line
然后在管理类中,我导入了这个新创建的子类,而不是原来的那个。EquipmentViewRoot(ModelView) 类现在重写了 on_model_change() 方法,在这里,如果上传了照片,就会明确执行以下指令:
form.photo.populate_obj(model, 'photo')
注意:我还没有在 InLineFieldList 上测试这个修复,现在的照片是一个单独的 ImageUploadField。