在利用flask 框架开发blog系统时,需要提供用户上传头像的功能,我们查看 flask wtf 文档 发现可以利用flask wtf 表单控件来实现文件上传。于是我们首先实现了如下的更新用户资料的表单代码:
class EditProfileForm(Form):
name = StringField('Real name',validators=[Length(0,64)])
location = StringField('Location',validators=[Length(0,64)])
about_me = TextAreaField('About me')
image = FileField('Your Photo')
submit = SubmitField('submit')
其中image属性是一个FileFiled控件,用来接收用户上传的头像图片。
然后还需要在view部分实现相应的路由,代码如下:
#view 部分实现的更新资料路由
@main.route('/edit-profile',methods=['GET','POST'])
@login_required
def edit_profile():
form = EditProfileForm()
if form.validate_on_submit():
current_user.name = form.name.data
current_user.location = form.location.data
current_user.about_me = form.about_me.data
filename = secure_filename(form.image.data.filename)
form.image.data.save(./uploads/ + filename)
current_user.image = './uploads/' + filename
db.session.add(current_user)
#db.session.rollback()
flash('Your Profile has been updated')
return redirect(url_for('.user',username=current_user.username))
form.name.data = current_user.name
form.location.data = current_user.location
form.about_me.data = current_user.about_me
return render_template('edit_profile.html',form=form)
代码看似没有问题,于是我们开始执行一下,然后发现了如下的错误:
IOError: [Errno 21] Is a directory: ‘./uploads/’
在百度中搜索,发现在stackoverflow上有相关的解决方案、
原来是在form.image.data.save
这个方法中需要提供绝对的路径,不能提供像./uploads/
这种相对的路径。于是我们修改代码如下:
import os
from werkzeug import secure_filename
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
UPLOAD_FOLDER = os.path.join(APP_ROOT, './uploads')
@main.route('/edit-profile',methods=['GET','POST'])
@login_required
def edit_profile():
............
form.image.data.save(UPLOAD_FOLDER + filename)
current_user.image = APP_ROOT +'/uploads/' + filename
....................
我们利用 os.path.dirname
和 os.path.join
来得到绝对的路径名称,然后提供给form.image.data.save
方法使用。
这样再执行代码,发现前面的IOError: [Errno 21] Is a directory: './uploads/'
错误不见了,顿时心里很开心。但是问题又来了,在我们测试的时候,图片并没有上传到我们制定的uploads文件夹,而且图片的名字的前缀是uploads。直觉告诉我们这肯定是把路径的名字写到文件名中了。于是我们继续查看保存图片的代码,然后发现了一处细微的错误:
UPLOAD_FOLDER = os.path.join(APP_ROOT, './uploads')
此处应该写成UPLOAD_FOLDER = os.path.join(APP_ROOT, './uploads/')
然后我们再测试代码,发现已经可以正常工作了。