提交后不刷新页面清空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
相关产品推荐
相关产品推荐

