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

Flask+SQLite用户资料页面无法更新数据库问题求助

Flask用户资料编辑功能修复方案

问题核心分析

  1. 编辑表单未同步用户数据:edit_account函数仅处理头像字段,未将表单其他修改字段同步到current_user对象,且db.session.commit()错误传入参数,导致数据库无更新。
  2. 路由扩展性不足:当前/profile路由仅支持展示登录用户信息,无法满足后续查看其他用户资料的需求。
  3. 密码字段处理错误:GET请求时将哈希后的密码赋值给表单,提交时未重新生成哈希,且未判断密码是否为空。

分步修复方案

一、修复edit_account函数逻辑

修改views.py中的edit_account函数,完善数据更新流程:

  1. 移除GET请求中多余的db.session.commit()(仅填充表单无需提交数据库)。
  2. 提交表单时,将所有字段赋值给current_user对象。
  3. 单独处理密码:仅当用户输入新密码时,重新生成哈希值存入数据库。
  4. 修正db.session.commit()调用方式(无需传入参数)。
  5. 导入User模型,解决未定义错误。

二、优化资料页路由(支持扩展)

将/profile改为动态路由,同时保留默认跳转登录用户资料页的逻辑:

  1. 新增/profile/<int:user_id>动态路由,用于查看指定用户资料。
  2. 原/profile路由重定向到当前登录用户的资料页。

修改后的完整代码

Views.py

from models import User
from flask import request, redirect, url_for, flash, render_template
from flask_login import login_required, current_user
from forms import UpdateUserForm
from app import db
import os
from werkzeug.utils import secure_filename
from werkzeug.security import generate_password_hash

# 实现头像上传保存逻辑
def add_profile_pic(pic_upload, username):
    filename = secure_filename(pic_upload.filename)
    save_path = os.path.join(os.getcwd(), 'static', 'profile_pics', f'{username}_{filename}')
    pic_upload.save(save_path)
    return f'{username}_{filename}'

@users.route('/edit_account', methods=['GET', 'POST'])
@login_required
def edit_account():
    form = UpdateUserForm()
    if form.validate_on_submit():
        # 更新基础信息字段
        current_user.username = form.username.data
        current_user.email = form.email.data
        current_user.fname = form.fname.data
        current_user.lname = form.lname.data
        current_user.phone = form.phone.data
        current_user.address = form.address.data
        current_user.postcode = form.postcode.data

        # 仅当输入新密码时更新哈希值
        if form.password.data:
            current_user.password_hash = generate_password_hash(form.password.data)

        # 处理头像上传
        if form.picture.data:
            pic = add_profile_pic(form.picture.data, current_user.username)
            current_user.profile_image = pic  

        # 提交数据库修改
        db.session.commit()
        flash('你的账户已更新')
        return redirect(url_for('users.profile', user_id=current_user.id))

    elif request.method == 'GET':
        # 填充表单现有数据(密码字段不显示哈希值)
        form.username.data = current_user.username
        form.email.data = current_user.email
        form.fname.data = current_user.fname
        form.lname.data = current_user.lname
        form.phone.data = current_user.phone
        form.address.data = current_user.address
        form.postcode.data = current_user.postcode

    profile_image = url_for('static', filename='profile_pics/'+current_user.profile_image)
    return render_template('edit_account.html', profile_image=profile_image, form=form)

# 动态路由:查看指定用户资料
@users.route('/profile/<int:user_id>')
@login_required
def profile(user_id):
    user = User.query.get_or_404(user_id)
    return render_template('profile.html', user=user)

# 默认路由:跳转当前登录用户资料页
@users.route('/profile')
@login_required
def default_profile():
    return redirect(url_for('users.profile', user_id=current_user.id))

Profile.html(适配动态路由)

将模板中current_user改为传入的user变量,仅登录用户能看到自己的编辑按钮:

{% extends "base.html" %}
{% block content %}

<div class="container emp-profile">
    <form method="post">
        <div class="row">
            <div class="col-md-4">
                <div class="profile-img">
                    <img src="{{ url_for('static', filename='profile_pics/'+user.profile_image )}}" alt="Profile Picture">
                </div>
            </div>
            <div class="col-md-6">
                <div class="profile-head">
                    <h5>Meet {{ user.username }}</h5>
                    <ul class="nav nav-tabs" id="myTab" role="tablist">
                        <li class="nav-item" role="presentation">
                            <button class="nav-link active" id="home-tab" data-bs-toggle="tab" data-bs-target="#home-tab-pane" type="button" role="tab" aria-controls="home-tab-pane" aria-selected="true">About</button>
                        </li>
                        <li class="nav-item" role="presentation">
                            <button class="nav-link" id="profile-tab" data-bs-toggle="tab" data-bs-target="#profile-tab-pane" type="button" role="tab" aria-controls="profile-tab-pane" aria-selected="false">Timeline</button>
                        </li>
                    </ul>
                </div>
            </div>
            <div class="col-md-2">
                {% if current_user.id == user.id %}
                <a class="btn btn-primary" href="{{ url_for('users.edit_account') }}" class="profile-edit-btn" name="btnAddMore">Edit Profile</a>
                {% endif %}
            </div>
        </div>
        <div class="row">
            <div class="col-md-4">
                <div class="profile-work">
                    <p>ABOUT</p>
                    <h6>Name: {{ user.fname }}</h6><br/>
                    <a href="">Bootsnipp Profile</a><br/>
                    <a href="">Bootply Profile</a>
                    <p>SKILLS</p>
                    <a href="">Web Designer</a><br/>
                    <a href="">Web Developer</a><br/>
                    <a href="">WordPress</a><br/>
                    <a href="">WooCommerce</a><br/>
                    <a href="">PHP, .Net</a><br/>
                </div>
            </div>
            <div class="col-md-8">
                <div class="tab-content profile-tab" id="myTabContent">
                    <div class="tab-pane fade show active" id="home-tab-pane" role="tabpanel" aria-labelledby="home-tab">
                        <div class="row">
                            <div class="col-md-6">
                                <label>Username</label>
                            </div>
                            <div class="col-md-6">
                                <p>{{ user.username }}</p>
                            </div>
                        </div>
                        <div class="row">
                            <div class="col-md-6">
                                <label>Name</label>
                            </div>
                            <div class="col-md-6">
                                <p>{{ user.fname }} {{ user.lname }}</p>
                            </div>
                        </div>
                        <div class="row">
                            <div class="col-md-6">
                                <label>Email</label>
                            </div>
                            <div class="col-md-6">
                                <p>{{ user.email }}</p>
                            </div>
                        </div>
                        <div class="row">
                            <div class="col-md-6">
                                <label>Phone</label>
                            </div>
                            <div class="col-md-6">
                                <p>{{ user.phone }}</p>
                            </div>
                        </div>
                        <div class="row">
                            <div class="col-md-6">
                                <label>Profession</label>
                            </div>
                            <div class="col-md-6">
                                <p>Driving Instructor</p>
                            </div>
                        </div>
                    </div>
                    <div class="tab-pane fade" id="profile-tab-pane" role="tabpanel" aria-labelledby="profile-tab">
                        <div class="row">
                            <div class="col-md-6">
                                <label>Teaches</label>
                            </div>
                            <div class="col-md-6">
                                <p>Manual Gearbox</p>
                            </div>
                        </div>
                        <div class="row">
                            <div class="col-md-6">
                                <label>Hourly Rate</label>
                            </div>
                            <div class="col-md-6">
                                <p>£40/hr</p>
                            </div>
                        </div>
                        <div class="row">
                            <div class="col-md-6">
                                <label>Car</label>
                            </div>
                            <div class="col-md-6">
                                <p>Audi A1 TFSI Sportback 2019</p>
                            </div>
                        </div>
                        <div class="row">
                            <div class="col-md-6">
                                <label>Years of experience</label>
                            </div>
                            <div class="col-md-6">
                                <p>1yr</p>
                            </div>
                        </div>
                        <div class="row">
                            <div class="col-md-6">
                                <label>Availability</label>
                            </div>
                            <div class="col-md-6">
                                <p>6 months</p>
                            </div>
                        </div>
                        <div class="row">
                            <div class="col-md-12">
                                <label>Your Bio</label><br/>
                                <p>Your detail description</p>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </form>           
</div>

{% endblock %}

Forms.py(添加唯一性验证)

避免用户名和邮箱重复提交冲突:

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, FileField, SubmitField
from wtforms.validators import Email, DataRequired, ValidationError
from models import User
from flask_login import current_user

class UpdateUserForm(FlaskForm):
    email = StringField('Email', validators=[Email(), DataRequired()])
    password = PasswordField('Password', validators=[])
    username = StringField('Username', validators=[DataRequired()])
    picture = FileField('Update profile picture', validators=[FileAllowed(['jpg','png'])]) 
    fname = StringField('First name', validators=[])
    lname = StringField('Last name', validators=[])
    phone = StringField('Phone', validators=[])
    address = StringField('Address(excluding postcode)', validators=[])
    postcode = StringField('Postcode', validators=[])
    submit = SubmitField('Confirm Update')

    def validate_username(self, username):
        if username.data != current_user.username:
            if User.query.filter_by(username=username.data).first():
                raise ValidationError('该用户名已被使用,请选择其他用户名。')

    def validate_email(self, email):
        if email.data != current_user.email:
            if User.query.filter_by(email=email.data).first():
                raise ValidationError('该邮箱已被注册,请使用其他邮箱。')

额外说明

  1. 确保static/profile_pics目录存在并具备写入权限,否则头像上传会失败。
  2. 密码字段为空时,不会修改数据库中的密码哈希值,保留原密码。
  3. 动态路由支持后续扩展查看其他用户资料,同时兼容原有登录用户的访问逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 07:37:01