flask框架应用之--文件上传

本文介绍如何使用Flask处理文件上传,包括安装配置环境、编写上传程序,并演示了具体操作步骤。

前言

用 Flask 处理文件上传比较方便。已上传的文件存储在内存或是文件系统中一个临时的位置。你可以通过请求对象的 files 属性访问它们。每个上传的文件都会存储在这个字典里。它表现近乎为一个标准的 Python file 对象,但它还有一个 save() 方法,这个方法允许你把文件保存到服务器的文件系统上。

一、环境

redhat7.0 server2 172.25.27.2
系统自带python2.7

二、flask框架安装

这里示范的是virtualenv中的 Flask安装
virtualenv 为每个不同项目提供一份 Python 安装。它并没有真正安装多个 Python 副本,但是它确实提供了一种巧妙的方式来让各项目环境保持独立。

[root@localhost ~]# wget https://pypi.python.org/packages/source/s/setuptools/setuptools-7.0.tar.gz
[root@localhost ~]# wget https://pypi.python.org/packages/11/b6/abcb525026a4be042b486df43905d6893fb04f05aac21c32c638e939e447/pip-9.0.1.tar.gz#md5=35f01da33009719497f01a4ba69d63c9
[root@localhost ~]# ls
pip-9.0.1.tar.gz  setuptools-7.0.tar.gz
[root@localhost ~]# tar -zxf pip-9.0.1.tar.gz
[root@localhost ~]# tar -zxf setuptools-7.0.tar.gz
[root@localhost ~]# cd pip-9.0.1/
[root@localhost pip-9.0.1]# python setup.py install
[root@localhost pip-9.0.1]# cd ../setuptools-7.0/
[root@localhost setuptools-7.0]# python setup.py install
[root@localhost ~]# pip install virtualenv
[root@localhost ~]# mkdir myproject
[root@localhost ~]# cd myproject
[root@localhost myproject]# virtualenv venv
New python executable in /root/myproject/venv/bin/python
Installing setuptools, pip, wheel...done.
[root@localhost myproject]# . venv/bin/activate
(venv) [root@localhost myproject]#

现在应该已经激活了 virtualenv(注意你的 shell 提示符显示的是当前活动的环境)。
现在你只需要键入以下的命令来激活 virtualenv 中的 Flask:

(venv) [root@localhost myproject]# pip install Flask

要退出virtualenv环境用以下命令

(venv) [root@localhost myproject]# deactivate 
[root@localhost myproject]# 

三、部署开始

1.安装uWSGI
(venv) [root@localhost myproject]# yum install -y python-devel
(venv) [root@localhost myproject]# pip install uwsgi
2.创建上传程序

有pycharm就可以直接使用pycharm来写,非常方便,一个文件就搞定,程序代码如下

# -*- coding: utf-8 -*-
import os
from flask import Flask, request, url_for, send_from_directory
from werkzeug import secure_filename

ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg', 'gif'])

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = os.getcwd()
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024


html = '''
    <!DOCTYPE html>
    <title>Upload File</title>
    <h1>图片上传</h1>
    <form method=post enctype=multipart/form-data>
         <input type=file name=file>
         <input type=submit value=上传>
    </form>
    '''


def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS


@app.route('/uploads/<filename>')
def uploaded_file(filename):
    return send_from_directory(app.config['UPLOAD_FOLDER'],
                               filename)


@app.route('/', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        file = request.files['file']
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            file_url = url_for('uploaded_file', filename=filename)
            return html + '<br><img src=' + file_url + '>'
    return html


if __name__ == '__main__':
    app.run()
3.关闭防火墙、iptables及selinux,然后在pycharm里直接运行,或者

python upload.py runserver 127.0.0.1:5000
在这里插入图片描述

4.验证上传文件

浏览器打开 127.0.0.1:5000
在这里插入图片描述
回到pycharm看刚才上传的文件,和代码放在了同一目录下,上传成功

在这里插入图片描述在这里插入图片描述

<think>我们被要求使用Flask-WTF与AJAX配合使用。AJAX允许异步提交表单,无需刷新页面。 关键点: 1. 在Flask-WTF中,表单通常通过POST请求提交,但AJAX通常使用JSON格式发送数据。 2. 我们需要在客户端使用JavaScript捕获表单提交事件,然后使用AJAX发送数据到服务器。 3. 服务器端需要能够处理AJAX请求,并返回JSON响应。 步骤: 1. 设置Flask-WTF表单(包括CSRF保护) 2. 在模板中,使用JavaScript拦截表单提交事件,然后通过AJAX发送表单数据。 3. 在视图函数中,检查请求是否是AJAX(通过`request.is_xhr`或`request.headers.get('X-Requested-With') == 'XMLHttpRequest'`),然后进行处理并返回JSON响应。 注意:由于Flask-WTF表单默认使用CSRF保护,所以在AJAX请求中需要包含CSRF令牌。 如何在AJAX中发送CSRF令牌? 方法1:在表单中生成一个隐藏字段包含CSRF令牌(Flask-WTF自动生成),然后在AJAX提交时获取该字段的值,并随数据一起发送。 方法2:将CSRF令牌存储在meta标签中(例如在HTML头部:`<meta name="csrf-token" content="{{ csrf_token() }}">`),然后在AJAX请求头中设置X-CSRFToken。 我们推荐方法2,因为这样不需要每个表单都单独处理。 示例步骤: 一、在基础模板中设置meta标签(例如在head部分): ```html <meta name="csrf-token" content="{{ csrf_token() }}"> ``` 二、编写JavaScript(使用jQuery为例)来设置AJAX请求的全局头: ```javascript // 使用jQuery $.ajaxSetup({ beforeSend: function(xhr, settings) { if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", $('meta[name="csrf-token"]').attr('content')); } } }); ``` 或者使用原生JavaScript也可以,但通常jQuery更方便。 三、创建表单: 假设有一个简单的登录表单(LoginForm),包含用户名密码。 四、视图函数: 需要处理两种请求:普通GET请求(返回表单页面)AJAX POST请求(返回JSON)。 五、模板中的表单: 正常使用Flask-WTF渲染表单,但注意不要使用form的action属性(或者留空),因为我们通过AJAX提交。 六、AJAX提交表单: 为表单的submit事件绑定处理函数,在该函数中收集表单数据,通过AJAX发送。 七、服务器端处理: - 验证表单数据 - 如果验证通过,执行相应的操作(例如登录用户) - 返回JSON格式的响应,例如:{ "success": true, "message": "登录成功" } 或者错误信息 示例代码: 1. 表单类(forms.py): ```python from flask_wtf import FlaskForm from wtforms import StringField, PasswordField from wtforms.validators import DataRequired class LoginForm(FlaskForm): username = StringField('用户名', validators=[DataRequired()]) password = PasswordField('密码', validators=[DataRequired()]) ``` 2. 视图函数(app.py): ```python from flask import jsonify, render_template, request @app.route('/login', methods=['GET', 'POST']) def login(): form = LoginForm() if form.validate_on_submit(): # 正常提交的处理逻辑 # 但如果是AJAX请求,我们返回JSON if request.is_xhr: # 或者 request.headers.get('X-Requested-With') == 'XMLHttpRequest' # 这里处理登录逻辑,省略具体验证 # 假设验证通过 return jsonify(success=True, message='登录成功') else: # 非AJAX提交,正常重定向等 # ... 这里省略 # 如果是GET或者是验证失败(且非AJAX)则渲染模板 # 如果是AJAX且验证失败,返回错误信息 if request.is_xhr: # 返回JSON格式的错误信息 errors = {field.name: field.errors for field in form if field.errors} return jsonify(success=False, errors=errors), 400 return render_template('login.html', form=form) ``` 注意:上述代码中,我们使用`request.is_xhr`来判断是否是AJAX请求,但注意这个属性在较新的Flask中已经被标记为废弃,推荐使用: `request.headers.get('X-Requested-With') == 'XMLHttpRequest'` 3. 模板(login.html)示例: ```html {% extends "base.html" %} {% block content %} <form id="login-form" method="POST"> {{ form.hidden_tag() }} {# 包含CSRF令牌的隐藏字段 #} {{ form.username.label }} {{ form.username() }} {{ form.password.label }} {{ form.password() }} <button type="submit">登录</button> </form> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script> $(document).ready(function() { $('#login-form').on('submit', function(e) { e.preventDefault(); // 阻止默认提交行为 var form = $(this); // 使用AJAX提交表单 $.ajax({ type: form.attr('method'), url: form.attr('action'), // 如果没有设置action,默认提交到当前URL data: form.serialize(), // 序列化表单数据 success: function(response) { if (response.success) { alert('成功:' + response.message); // 可以重定向到其他页面,例如:window.location.href = '/dashboard'; } else { // 显示错误信息 alert('失败:' + JSON.stringify(response.errors)); } }, error: function() { alert('请求失败'); } }); }); }); </script> {% endblock %} ``` 注意:这里我们使用了jQuery的`serialize()`方法来序列化表单数据,它会自动包括隐藏字段(如CSRF令牌)。同时,我们在基础模板中已经设置了全局的AJAX CSRF令牌(通过上面的ajaxSetup),所以这里不需要额外设置。 但是,由于我们在表单中已经包含了CSRF令牌(通过`{{ form.hidden_tag() }}`),所以序列化数据中已经包含了它。另外,我们之前设置的全局AjaxSetup也会在请求头中设置CSRF令牌,这样可能会发送两次。不过,Flask-WTF会检查请求头中的X-CSRFToken,如果存在则优先使用,所以不会冲突。但为了保险起见,我们可以只使用其中一种方式。 推荐做法:使用全局设置(ajaxSetup)设置请求头,这样就不需要在每个表单中单独处理,而且对于非表单的AJAX请求(如删除操作)也可以使用。 因此,我们可以不在表单中放置CSRF令牌的隐藏字段(即去掉`{{ form.hidden_tag() }}`),而是完全通过请求头传递。但是,Flask-WTF表单默认需要这个字段。所以,为了简化,我们通常保留隐藏字段,同时设置请求头,这样即使一种方式失败,另一种方式也能起作用。 另外,如果不想使用全局ajaxSetup,也可以在每次AJAX请求前单独设置请求头。 对于不使用jQuery的情况,可以使用Fetch API,并手动设置请求头。 总结:使用Flask-WTF配合AJAX,主要注意两点: 1. 在AJAX请求中包含CSRF令牌(通过隐藏字段或请求头) 2. 在视图函数中判断AJAX请求并返回JSON响应。 以上是一个基本示例,实际应用中可能需要更详细的错误处理用户反馈。 </think>### Flask-WTF与AJAX配合使用方法详解 在Flask应用中,Flask-WTF与AJAX配合使用可以实现无刷新表单提交,提升用户体验。以下是完整实现方案: #### 1. **基础配置** 需在基础模板中设置CSRF令牌(AJAX请求必需): ```html <!-- base.html --> <head> <meta name="csrf-token" content="{{ csrf_token() }}"> </head> ``` #### 2. **前端AJAX处理** 使用jQuery发送表单数据并处理响应: ```javascript $(document).ready(function() { $('#your-form-id').submit(function(e) { e.preventDefault(); $.ajax({ type: "POST", url: $(this).attr('action'), data: $(this).serialize(), headers: { "X-CSRFToken": $('meta[name="csrf-token"]').attr('content') // 关键:传递CSRF令牌 }, success: function(response) { if (response.success) { $("#result").html("操作成功: " + response.message); } else { $("#errors").html(response.errors.join("<br>")); } }, error: function() { alert("服务器错误"); } }); }); }); ``` #### 3. **Flask视图处理** 在视图函数中区分AJAX请求与普通请求: ```python from flask import jsonify, request @app.route('/submit', methods=['POST']) def submit_form(): form = YourForm() if form.validate(): # 表单验证 # 业务逻辑处理(示例) result = process_data(form.data) if request.headers.get('X-Requested-With') == 'XMLHttpRequest': # 识别AJAX请求 return jsonify(success=True, message="数据提交成功", new_data=result) else: return render_template('result.html', result=result) else: # 验证失败 if request.is_xhr: # 兼容旧版Flask errors = [f"{field}: {', '.join(err)}" for field, err in form.errors.items()] return jsonify(success=False, errors=errors), 400 return render_template('form.html', form=form) ``` #### 4. **关键注意事项** 1. **CSRF保护** - 必须通过`headers`传递`X-CSRFToken` - 禁用CSRF:`form = YourForm(meta={'csrf': False})`(不推荐) 2. **文件上传处理** 使用`FormData`对象: ```javascript let formData = new FormData($('#form')[0]); $.ajax({ processData: false, // 必要设置 contentType: false, data: formData }) ``` 3. **JSON数据接收** 如需接收纯JSON: ```python data = request.get_json() form = YourForm(data=data, meta={'csrf': False}) ``` #### 5. **完整工作流程** ```mermaid graph TD A[用户填写表单] --> B[jQuery阻止默认提交] B --> C[序列化表单数据] C --> D[携带CSRF令牌发送AJAX] D --> E[Flask路由接收] E --> F{表单验证} F -- 成功 --> G[处理业务逻辑] F -- 失败 --> H[返回错误JSON] G --> I[返回成功JSON] I --> J[jQuery更新DOM] ``` > **最佳实践建议** > 1. 始终开启CSRF保护防止跨站攻击[^1] > 2. AJAX响应统一使用HTTP状态码(200成功,400验证失败) > 3. 对敏感操作添加二次确认 > 4. 使用Flask-DebugToolbar调试AJAX请求
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值