You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

提交后不刷新页面清空Flask表单的实现方案

问题描述

用Flask开发简易待办清单应用,已创建添加任务的Flask Form。提交任务后页面刷新,表单保留之前输入内容,刷新会导致重复提交。试过设置default值、编写函数重置为空字符串等方法都无效,需要实现提交后不刷新页面且清空表单的方案。

Flask Form代码

class AddTask(FlaskForm):
    title = StringField('Title', validators = [DataRequired()])
    description = StringField('Description')
    project = SelectField('Project', choices = [], validators = [DataRequired()])
    due_date_time = DateField('Due Date', format = '%Y-%m-%d')
    priority = RadioField('Priority', choices = [(1, 'Priority 1'), (2, 'Priority 2'), (3, 'Priority 3'), (4, 'Priority 4')])
    submit = SubmitField('Add Task')
    attributes_to_clear = [title, description, project, due_date_time, priority]

HTML模板代码

<div class = "new_task_form">
        <form action = "/app/today" method = "POST">
            {{ new_task_form.hidden_tag() }}
            {{ new_task_form.csrf_token }}
            {{ new_task_form.title.label }}
            {{ new_task_form.title }}
            {% if new_task_form.title.errors %}
                <ul class="errors">
                    {% for error in new_task_form.errors %}
                        <li>{{ error }}</li>
                    {% endfor %}
                </ul>
            {% endif %}
            {{ new_task_form.description.label }}
            {{ new_task_form.description }}
            {{ new_task_form.project.label }}
            {{ new_task_form.project }}
            {{ new_task_form.due_date_time.label }}
            {{ new_task_form.due_date_time }}
            {{ new_task_form.priority.label }}
            {{ new_task_form.priority }}
            {{ new_task_form.submit() }}
        </form>
    </div>

Flask路由代码

@app.route('/app/today', methods = ['POST', 'GET'])
@login_required
def today():
    today = datetime.today().strftime('%a %b %d')
    projects = [(project.id, project.title) for project in Project.query.filter(Project.user_id == current_user.id).all()]
    new_task_form = AddTask()
    new_task_form.project.choices = projects
    logger.info(f'new_task_form.project.choices: {new_task_form.project.choices}')
    if new_task_form.validate_on_submit():
        logger.info(f'new_task_form.validate_on_submit() returned {new_task_form.validate_on_submit()}')
        project_from_form = Project.query.filter(Project.id == new_task_form.project.data).first()
        logger.error(f'project_from_form: {project_from_form}')
        new_task = Task(
            title = new_task_form.title.data,
            description = new_task_form.description.data,
            project = project_from_form,
            due_date_time = new_task_form.due_date_time.data,
            priority_level = new_task_form.priority.data,
            user_id = current_user.id
        )
        db.session.add(new_task)
        db.session.commit()
    else:
        logger.info(f'new_task_form.validate_on_submit(): Returned {new_task_form.validate_on_submit()}')
        logger.info(f'new_task_form.errors: {new_task_form.errors}')
    pending_tasks = Task.query.filter(Task.user_id == current_user.id, Task.completed_status == 0).all()
    pending_tasks_length = len(pending_tasks)
    logger.info(f'current_user: {current_user.id}')
    logger.info(f'pending_tasks_length: {pending_tasks_length}')
    logger.info(f'pending_tasks: {pending_tasks}')
    return render_template('today.html',
        day_and_date = today,
        new_task_form = new_task_form,
        user_projects = projects,
        pending_tasks_length = pending_tasks_length,
        pending_tasks = pending_tasks)
解决方案

方案一:PRG模式解决重复提交(页面仍刷新,但避免重复提交)

PRG是Web开发解决重复提交的标准方案,提交成功后重定向回当前页面,浏览器执行GET请求,不会重复提交表单,同时新生成的表单为空。

修改路由代码:

from flask import redirect, url_for

@app.route('/app/today', methods = ['POST', 'GET'])
@login_required
def today():
    today = datetime.today().strftime('%a %b %d')
    projects = [(project.id, project.title) for project in Project.query.filter(Project.user_id == current_user.id).all()]
    new_task_form = AddTask()
    new_task_form.project.choices = projects
    logger.info(f'new_task_form.project.choices: {new_task_form.project.choices}')
    if new_task_form.validate_on_submit():
        logger.info(f'new_task_form.validate_on_submit() returned {new_task_form.validate_on_submit()}')
        project_from_form = Project.query.filter(Project.id == new_task_form.project.data).first()
        logger.error(f'project_from_form: {project_from_form}')
        new_task = Task(
            title = new_task_form.title.data,
            description = new_task_form.description.data,
            project = project_from_form,
            due_date_time = new_task_form.due_date_time.data,
            priority_level = new_task_form.priority.data,
            user_id = current_user.id
        )
        db.session.add(new_task)
        db.session.commit()
        # 提交成功后重定向回当前页面
        return redirect(url_for('today'))
    else:
        logger.info(f'new_task_form.validate_on_submit(): Returned {new_task_form.validate_on_submit()}')
        logger.info(f'new_task_form.errors: {new_task_form.errors}')
    pending_tasks = Task.query.filter(Task.user_id == current_user.id, Task.completed_status == 0).all()
    pending_tasks_length = len(pending_tasks)
    logger.info(f'current_user: {current_user.id}')
    logger.info(f'pending_tasks_length: {pending_tasks_length}')
    logger.info(f'pending_tasks: {pending_tasks}')
    return render_template('today.html',
        day_and_date = today,
        new_task_form = new_task_form,
        user_projects = projects,
        pending_tasks_length = pending_tasks_length,
        pending_tasks = pending_tasks)

方案二:AJAX实现无刷新提交+清空表单(满足不刷新页面需求)

通过JavaScript发送AJAX请求提交数据,完成后手动清空表单并更新页面内容,无需整页刷新。

步骤1:新增AJAX处理路由

添加专门处理任务提交的POST接口,返回JSON结果:

from flask import jsonify

@app.route('/app/add-task', methods=['POST'])
@login_required
def add_task():
    new_task_form = AddTask()
    projects = [(project.id, project.title) for project in Project.query.filter(Project.user_id == current_user.id).all()]
    new_task_form.project.choices = projects
    
    if new_task_form.validate_on_submit():
        project_from_form = Project.query.filter(Project.id == new_task_form.project.data).first()
        new_task = Task(
            title = new_task_form.title.data,
            description = new_task_form.description.data,
            project = project_from_form,
            due_date_time = new_task_form.due_date_time.data,
            priority_level = new_task_form.priority.data,
            user_id = current_user.id
        )
        db.session.add(new_task)
        db.session.commit()
        # 返回成功信息和新任务数据(用于更新页面)
        return jsonify({
            'success': True,
            'task': {
                'title': new_task.title,
                'description': new_task.description,
                'due_date': new_task.due_date_time.strftime('%Y-%m-%d') if new_task.due_date_time else '',
                'priority': new_task.priority_level
            }
        })
    else:
        # 返回错误信息
        return jsonify({'success': False, 'errors': new_task_form.errors}), 400

步骤2:修改HTML表单,添加ID方便JS操作

给表单和元素添加ID,便于JavaScript获取和操作:

<div class = "new_task_form">
    <form id="addTaskForm">
        {{ new_task_form.hidden_tag() }}
        {{ new_task_form.csrf_token }}
        <div>
            {{ new_task_form.title.label }}
            {{ new_task_form.title(id="taskTitle") }}
            {% if new_task_form.title.errors %}
                <ul class="errors">
                    {% for error in new_task_form.title.errors %}
                        <li>{{ error }}</li>
                    {% endfor %}
                </ul>
            {% endif %}
        </div>
        <div>
            {{ new_task_form.description.label }}
            {{ new_task_form.description(id="taskDescription") }}
        </div>
        <div>
            {{ new_task_form.project.label }}
            {{ new_task_form.project(id="taskProject") }}
        </div>
        <div>
            {{ new_task_form.due_date_time.label }}
            {{ new_task_form.due_date_time(id="taskDueDate") }}
        </div>
        <div>
            {{ new_task_form.priority.label }}
            {{ new_task_form.priority(id="taskPriority") }}
        </div>
        <button type="button" id="submitTaskBtn">{{ new_task_form.submit.label.text }}</button>
    </form>
    <!-- 任务列表容器 -->
    <div id="pendingTasksList">
        {% for task in pending_tasks %}
            <div class="task-item">
                <h3>{{ task.title }}</h3>
                <p>{{ task.description }}</p>
                <p>截止日期: {{ task.due_date_time.strftime('%Y-%m-%d') if task.due_date_time else '无' }}</p>
                <p>优先级: Priority {{ task.priority_level }}</p>
            </div>
        {% endfor %}
    </div>
</div>

步骤3:添加JavaScript处理AJAX提交

在HTML模板末尾添加脚本:

document.getElementById('submitTaskBtn').addEventListener('click', function() {
    // 收集表单数据
    const formData = new FormData();
    formData.append('title', document.getElementById('taskTitle').value);
    formData.append('description', document.getElementById('taskDescription').value);
    formData.append('project', document.getElementById('taskProject').value);
    formData.append('due_date_time', document.getElementById('taskDueDate').value);
    
    // 获取选中的优先级
    const priorityRadio = document.querySelector('input[name="priority"]:checked');
    if (priorityRadio) {
        formData.append('priority', priorityRadio.value);
    }
    
    // 添加CSRF令牌
    formData.append('csrf_token', document.querySelector('input[name="csrf_token"]').value);

    // 发送AJAX请求
    fetch('/app/add-task', {
        method: 'POST',
        body: formData
    })
    .then(response => response.json())
    .then(data => {
        if (data.success) {
            // 清空表单
            document.getElementById('addTaskForm').reset();
            // 更新任务列表,添加新任务
            const taskItem = document.createElement('div');
            taskItem.className = 'task-item';
            taskItem.innerHTML = `
                <h3>${data.task.title}</h3>
                <p>${data.task.description || ''}</p>
                <p>截止日期: ${data.task.due_date || '无'}</p>
                <p>优先级: Priority ${data.task.priority}</p>
            `;
            document.getElementById('pendingTasksList').prepend(taskItem);
            // 更新任务数量(如果页面有显示数量的元素)
            const countEl = document.querySelector('.pending-tasks-count');
            if (countEl) countEl.textContent = parseInt(countEl.textContent) + 1;
        } else {
            alert('提交失败: ' + JSON.stringify(data.errors));
        }
    })
    .catch(error => {
        console.error('提交出错:', error);
        alert('提交出错,请稍后重试');
    });
});

内容的提问来源于stack exchange,提问作者user21114274

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 23:08:11