【问题标题】:Why doesn't my list populated from a database refresh unless I restart my Flask server?为什么除非我重新启动 Flask 服务器,否则我的列表不会从数据库刷新中填充?
【发布时间】:2019-12-15 09:35:32
【问题描述】:

我有一个非常简单的烧瓶应用程序,它允许我注册用户名,然后在列表中显示这些名称。我可以注册,但列表将是空的。如果我重新启动烧瓶服务器,名称会在页面加载时出现。我尝试关闭/重新打开数据库,调用函数(populateuserlist)来刷新列表,并在 html 中禁用浏览器缓存无济于事。任何帮助将不胜感激!

app.py

from flask import Flask, render_template, url_for, request, render_template_string
from flask_wtf import FlaskForm
from wtforms import StringField, SelectField
from wtforms.validators import InputRequired, length
import sqlite3
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secretkey'
conn = sqlite3.connect('users.db')
c = conn.cursor()
#create users.db if it doesn't exist
try:
    c.execute("""CREATE TABLE users (
            username text UNIQUE
            )""")
    print("users.db created with users table")
except:
    print("users.db file exists")

c.execute("SELECT * FROM users")
userlist=c.fetchall()
conn.close()

#populate userlist from users.db
def populateuserlist():
    conn = sqlite3.connect('users.db')
    c = conn.cursor()
    c.execute("SELECT * FROM users")
    userlist = c.fetchall()
    conn.close()
    return userlist

#form with drop down list for users page
class selectuserform(FlaskForm):
    populateuserlist()
    userlist = populateuserlist()
    print("Login form populated with" + str(userlist) + ".")
    currentuser = SelectField('currentuser', choices=[(user[0], user[0]) for user in userlist])

class RegisterNameForm(FlaskForm):
    RegisterName = StringField('Username', validators= [InputRequired(), length(min=1, max=15)])

#define page routes
@app.route('/login', methods=['GET', 'POST'])
def login_page():
    form = RegisterNameForm()
    if form.validate_on_submit():
        newuser=request.form.get("RegisterName")
        conn = sqlite3.connect('users.db')
        c = conn.cursor()
        c.execute("INSERT OR IGNORE INTO users VALUES (?)", (newuser,))
        conn.commit()
        conn.close()

    form = selectuserform()
    populateuserlist()

    return render_template('login.html', userlist=userlist, form=form)

@app.route('/register', methods=['GET', 'POST'])
def register_page():
    form = RegisterNameForm()
    return render_template('register.html', form=form)

#start flask server
if __name__ == '__main__':
    app.run(debug=True)

login.html

<!<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">

</head>
<body>
<div>
    <button onclick="window.location.href = '/register'";>Register</button>
    <center>
        <h1>Select User</h1>
<form method="POST" ACTION="{{ url_for('login_page') }}">
    {{ form.csrf_token }}
    {{ form.currentuser }}
    <br><br>

    <input type="submit" value="Continue">
</form>
    </center>
</div>
</body>
</html>

register.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
    <button onclick="window.location.href = '/login'";>Go back</button>
    <center>
        <h1>Enter your name</h1>
        <form method="POST" action="/login">
        {{ form.hidden_tag() }}
        {{ form.RegisterName }}
            <br><br>
        <input type="submit" value="Create user">
        </form>
    </center>
</body>
</html>

【问题讨论】:

    标签: python sqlite flask


    【解决方案1】:

    您不应该在网络应用程序中使用这样的全局值,它会让您对各种不稳定的行为持开放态度。这个函数:

    def populateuserlist():
        conn = sqlite3.connect('users.db')
        c = conn.cursor()
        c.execute("SELECT * FROM users")
        userlist = c.fetchall()
        conn.close()
        return userlist 
    

    对全局 userlist 名称没有任何作用。为什么要呢?您在本地函数范围内创建一个新名称。我故意跳过global 的使用,你不应该尝试使用它。您可以通过以下方式轻松测试范围问题:

    a = [1, 2, 3]
    
    def something():
        a = [2, 3, 4]
        return a
    
    something()
    print(a)
    

    因此,userlist(全局)仅在应用启动时评估一次。相反,您需要在视图中调用populateuserlist(应该相应地重命名,因为它不会填充全局名称)。您的表单中也存在该问题。您需要动态更新选项列表。

    @app.route('/login', methods=['GET', 'POST'])
    def login_page():
        form = RegisterNameForm()
        if form.validate_on_submit():
            newuser=request.form.get("RegisterName")
            conn = sqlite3.connect('users.db')
            c = conn.cursor()
            c.execute("INSERT OR IGNORE INTO users VALUES (?)", (newuser,))
            conn.commit()
            conn.close()
    
        form = selectuserform()
        userlist = populateuserlist() # CHANGED HERE
        form.currentuser.choices = [(user[0], user[0]) for user in userlist] # ADD THE NEW OPTIONS (IF ANY)
    
        return render_template('login.html', userlist=userlist, form=form)
    

    【讨论】:

    • 我已经添加了 userlist = populateuserlist() 但它仍然没有刷新。我还在其下方添加了 print(userlist) ,控制台确实反映了数据库和用户列表值正在正确更新,但下拉列表未反映更改。也感谢您对全局变量和局部变量的出色解释,我对 python 很陌生。 populateuserlist 函数的更合适的名称是什么?
    • @Bob 最后一部分很简单; get_userlist() 是一个更好的名字,但让我再回顾一下代码,因为也许我错过了前端的一些东西
    • @Bob 明白了。给我几分钟编辑,我确实错过了一些东西
    • @Bob 已编辑但未经测试。让我知道这是否有效
    • 效果很好,也感谢您对函数命名的见解。
    猜你喜欢
    • 2015-03-09
    • 2022-01-18
    • 2021-12-30
    • 2021-05-14
    • 2013-07-17
    • 2020-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多