【问题标题】:How to replace an specific item of a dict in a .txt file database如何替换 .txt 文件数据库中 dict 的特定项目
【发布时间】:2017-11-02 21:50:28
【问题描述】:

我想使用 .txt 文件来存储应用程序的 API 令牌,但我在试图找到一种方法来替换文件中的 API 密钥/令牌时遇到了困难。这是尝试过的代码(Python 3.5)

data_to_save = {}
data_to_save['savetime'] = str(datetime.datetime.now())[:19]
data_to_save['api_key'] = key_submitted
data_to_save['user'] = uniqueid
api_exists = False
user_exists = False
with open("databases/api_keys.txt", 'r+') as f:
    database = json.loads(f.read())
    for i in database:
        if i['api_key'] == key_submitted:
            send_text_to_user(userid, "[b]Error: That API key is already in use.[/b]", "red")
            api_exists = True
        if i['user'] == uniqueid:
            user_exists = True
    if user_exists == True:
        if api_exists = True:
            send_text_to_user(userid, "[b]Error: Your API key was already saved at another time.[/b]", "red")
        else:
            f.write(json.dumps(data_to_save)) #Here, StackOverflow
            send_text_to_user(userid, "[b]Okay, I replaced your API key.[/b]", "green")
    f.close()
if user_exists == False:
    writing = open("databases/api_keys.txt", 'a')
    writing.write(json.dumps(data_to_save))
    writing.close()

我也想知道这是否是最好的方法,或者代码可以优化以及如何优化。

谢谢,已经搞定了。最终代码:

data_to_save = {'savetime': str(datetime.datetime.now())[:19], 'api_key': key_submitted, 'user': uniqueid}
with open("databases/api_keys.txt", 'r') as f:
    database = json.loads(f.read())
    for i in database:
        if i['user'] == uniqueid:
            database.remove(i)
        if i['api_key'] == key_submitted:
            send_text_to_user(userid, "[b]Error: That API key is already in use.[/b]", "red")
            api_exists = True
            break
    if not api_exists:
        database.append(data_to_save)
        f.write(json.dumps(database)
    send_text_to_user(userid, "[b]Okay, your API key was succesfully stored.[/b]")

使用这种方法,我们甚至不需要编写不同的保存,以防万一用户存在或不存在,因为如果找到它就会删除它,所以当代码运行时它永远不会存在,它只需要保存一个每次都“新”记录,除非 API 密钥已经属于另一个用户。

【问题讨论】:

  • if api_exists = True - if 语句中不允许赋值

标签: python database


【解决方案1】:

给定的代码有很多问题,所以让我们从头开始:

  1. 我们不需要创建空的dict 对象来填充下一行

    data_to_save = {}
    data_to_save['savetime'] = str(datetime.datetime.now())[:19]
    data_to_save['api_key'] = key_submitted
    data_to_save['user'] = uniqueid
    

    当我们可以创建它时填充像

    data_to_save = {'savetime': str(datetime.datetime.now())[:19],
                    'api_key': key_submitted,
                    'user': uniqueid}
    
  2. if 语句中不允许赋值(更多信息请参见docs

    if api_exists = True:
    

    所以这条线会导致SyntaxError(我猜这是一个错字)。

  3. 检查喜欢

    if user_exists == True:
        ...
    

    are redundant,我们可以写

    if user_exists:
        ...
    

    并具有相同的效果。

  4. 我们在使用with 语句时不需要显式关闭文件,这就是context managers 的作用:退出with 语句块后的清理。

  5. 您的databases/api_key.txt 文件在第一次迭代后将具有无效的JSON 对象,因为您只是在文件末尾写入新的序列化data_to_save 对象,而您应该修改database 对象(好像是一个字典列表)并写序列化的新版本,所以我们也不需要r+模式。

让我们定义保存新 API 密钥数据的实用函数,例如

def save_database(database,
                  api_keys_file_path="databases/api_keys.txt"):
    with open(api_keys_file_path, 'w') as api_keys_file:
        api_keys_file.write(json.dumps(database))

那么我们可以有类似的东西

data_to_save = {'savetime': str(datetime.datetime.now())[:19],
                'api_key': key_submitted,
                'user': uniqueid}
api_exists = False
user_exists = False
with open("databases/api_keys.txt", 'r') as api_keys_file:
    database = json.loads(api_keys_file.read())
    # database object should be iterable,
    # containing dictionaries as elements,
    # so only possible solution -- it is a list of dictionaries
    for i in database:
        if i['api_key'] == key_submitted:
            send_text_to_user(userid, "[b]Error: That API key is already in use.[/b]", "red")
            api_exists = True
        if i['user'] == uniqueid:
            user_exists = True

    if user_exists:
        if api_exists:
            send_text_to_user(userid, "[b]Error: Your API key was already saved at another time.[/b]", "red")
        else:
            # looking for user record in database
            user_record = next(record for record in database
                               if record['user'] == uniqueid)
            # setting new API key
            user_record['api_key'] = key_submitted
            save_database(database)
            send_text_to_user(userid, "[b]Okay, I replaced your API key.[/b]", "green")

if not user_exists:
    database.append(data_to_save)
    save_database(database)

示例

我用包含单行的api_keys.txt 文件创建了目录databases

[]

因为一开始我们没有 API 密钥。

假设我们错过的对象的定义如下

key_submitted = '699aa2c2f9fc41f880d6ec79a9d55f29'
uniqueid = 3
userid = 42


def send_text_to_user(userid, msg, color):
    print(msg)

所以使用上面的代码,它在第一次执行脚本时给了我空输出,而在第二次:

[b]Error: That API key is already in use.[/b]
[b]Error: Your API key was already saved at another time.[/b]

进一步改进

  • 如果满足条件之一(API 密钥或用户已在数据库中注册),我们是否应该从 for 循环 break
  • 也许使用已经编写好的数据库而不是重新发明轮子会更好?如果您需要 JSON 对象,您应该查看 TinyDB

【讨论】:

  • 我几乎是在没有教程的情况下通过反复试验来学习 python,所以这就是为什么我的代码有时如此随机的原因。也就是说... 1: 你说得对,我知道这个,但我想我太累了,看不到。 2: 是的,第 2 点完全是一个错字。 3: 哦,那很好。 4: 嗯,不知道这个,但本质上我猜它给出了相同的结果。 5: 这很聪明。我只是重新创建整个文件并写入它,而不是试图保持大部分文件不变并覆盖所需的数据。
  • 关于您提出的改进建议:我不想打破 for 循环,因为我想确保不同的用户不共享相同的 api 密钥(它必须是唯一的)。用户也一样,我不希望每个用户有 2 个不同的条目,所以我尝试了 for 循环以标记该用户或 api 密钥(或两者)存在,然后为每种情况做不同的事情。
  • @Saelyth:顺便说一句,为什么你不使用sqlite 或任何其他已编写好的、支持良好且稳定的数据库?
  • 所以你的代码到目前为止对我有帮助,但还没有完成。它缺少“如果用户已经保存了 api 密钥但它想用新的 api 密钥替换它”的情况。那就是我在#Here, stackoverflow 上发表评论的地方,这正是我寻求帮助的原因。
  • 要求我这样做的人不想使用合适的数据库并且拒绝安装任何软件(这就是为什么我什至没有尝试过 sqlite 或 TinyDB,而我选择使用.txt 文件)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-21
  • 2017-08-15
  • 2015-03-28
  • 2011-03-27
相关资源
最近更新 更多