【问题标题】:How to raise error message on duplicate entry while inserting data into sqlite3 with python?使用python将数据插入sqlite3时如何在重复条目上引发错误消息?
【发布时间】:2017-10-26 09:47:28
【问题描述】:

伙计们,我正在使用带有 python tkinter 作为前端的 sqlite3。该数据库是一个简单的数据库,有两个字段,usernamepassword。我想做一个注册注册页面。其中两个字段中给出的数据将存储在 sqlite3 数据库中。数据插入正确。但是当提供的用户名已经存在于数据库中时,我想显示一个消息框。我尝试了下面的代码。

我的密码:

def signup():
    userID = username.get()
    passwd = password.get()
    conn = sqlite3.connect('test.db')
    c = conn.cursor()
    result = c.execute("SELECT * FROM userstable")

    for i in result:
        if i[0] == userID:
            messagebox.showerror("DUPLICATE", "USER ALREADY EXISTS!")

    else:
        conn = sqlite3.connect('test.db')
        c = conn.cursor()
        c.execute("INSERT INTO userstable VALUES (?, ?)", (userID, passwd))
        conn.commit()
        c.close()
        conn.close()
        username.delete(0,END)
        password.delete(0,END)
        username.focus()
        messagebox.showinfo("SUCCESS", "USER CREATED SUCCESSFULLY")

这可行,但在出现错误消息后仍会存储重复的数据。如果用户名已经可用,我的要求是抛出错误并停止执行。如果用户名不可用,则应插入数据。

我哪里出错了?有人可以通过指出来解释我还是有其他方法可以实现这一点?看来我需要对我的功能进行一些修改。请指导我。

编辑 1

如果我尝试使用三个条件,则中断不起作用。

我的代码

def data_entry():
    conn = sqlite3.connect('test.db')
    c = conn.cursor()
    c.execute('CREATE TABLE IF NOT EXISTS userstable(username TEXT, password TEXT)')
    username = uname.get()
    password = passwd.get()

    result = c.execute("SELECT * FROM userstable")

    if username != '' or password != '':

        for i in result:
            if i[0] == username:
                tkinter.messagebox.showerror("DUPLICATE", "USER ALREADY EXISTS!")
                break
        else: 
            c.execute('INSERT INTO userstable (username, password) VALUES(?, ?)',(username,password))
            conn.commit()
            c.close()
            conn.close()
            another_clear()
            tkinter.messagebox.showinfo("Success", "User Created Successfully,\nPlease restart application.")

    else:
        tkinter.messagebox.showerror("ERROR", "Fill both fields!")

【问题讨论】:

  • 你知道这仍然不会阻止插入重复的用户名,对吧?仍然存在竞争条件(更不用说您必须在其他任何可能添加用户的小型维护工具或页面中重新实现该逻辑),您真的应该改用R. Scott's approach

标签: python tkinter sqlite


【解决方案1】:

解决此问题的更好方法是在表上创建唯一约束(索引,在 sqlite 中)以防止插入重复的用户名。这样,您可以尝试/排除插入语句,而不是遍历所有用户的列表以查看它是否已经存在(这是不可扩展的)。这也将阻止您必须“选择 *”,这通常是不好的做法(尽量明确)。

https://sqlite.org/lang_createtable.html

因此,您可以将约束添加为唯一索引或主键。如果您在此表中只有 2 列,或者您有超过 2 个但没有其他 ID,则您的用户名可以作为您的主键。如果您要为您的用户引入系统 ID,我会使用它作为您的主键和用户名作为唯一索引。无论哪种方式,您都需要更改表以添加约束。

CREATE UNIQUE INDEX username_uidx ON userstable (username);

同样,因为您没有明确让我们知道列名,所以您必须填写。

之后:

try:
    conn = sqlite3.connect('test.db')
    c = conn.cursor()
    c.execute("INSERT INTO userstable VALUES (?, ?)", (userID, passwd))
    conn.commit()
except: # I'm not sure the exact error that's raised by SQLite
    messagebox.showerror("DUPLICATE", "USER ALREADY EXISTS!")
finally:
    c.close()
    conn.close()

我通常将光标和连接包装在 finally 中,以便即使出现异常它们也会关闭。这不是您需要的 100%,但它应该通过更好的数据库设计让您一步到位,以强制用户的唯一性。

【讨论】:

    【解决方案2】:

    我建议不要使用带有 else 语句的循环,这可能会造成混淆。
    有关更多信息,请参阅此帖子 why-does-python-use-else-after-for-and-while-loops

    如果要使用for-else可以加个break,这样else就不会被执行:

    for i in result:
        if i[0] == userID:
            messagebox.showerror("DUPLICATE", "USER ALREADY EXISTS!")
            break
    else:
        ...
    

    或者你可以使用真/假标志:

    user_exists = False
    for i in result:
        if i[0] == userID:
            messagebox.showerror("DUPLICATE", "USER ALREADY EXISTS!")
            user_exists = True
    if not user_exists : 
        ...
    

    【讨论】:

    • 但是当我尝试三个条件时它不起作用
    • 例如,我想检查用户名和密码字段是否为空,如果是,它应该通过一个消息框,如果不是,它应该继续检查重复条目。如果两个条件都满足,则应将数据保存在表中
    • 谢谢@t.m.adam :)
    • 不客气。另外我认为您应该检查用户名 密码是否不为空,即:if username != '' and password != '':
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多