准备好待办事项数据库以供使用
准备好待办事项数据库以供使用
要准备好待办事项数据库以供使用,您需要执行两个操作。首先,您需要一种从应用程序的配置文件中检索数据库文件路径的方法。其次,您需要初始化数据库以保存 JSON 内容。
打开database.py
从rptodo/
你的代码编辑器,写了下面的代码:
"""This module provides the RP To-Do database functionality."""
# rptodo/database.py
import configparser
from pathlib import Path
from rptodo import DB_WRITE_ERROR, SUCCESS
DEFAULT_DB_FILE_PATH = Path.home().joinpath(
"." + Path.home().stem + "_todo.json"
)
def get_database_path(config_file: Path) -> Path:
"""Return the current path to the to-do database."""
config_parser = configparser.ConfigParser()
config_parser.read(config_file)
return Path(config_parser["General"]["database"])
def init_database(db_path: Path) -> int:
"""Create the to-do database."""
try:
db_path.write_text("[]") # Empty to-do list
return SUCCESS
except OSError:
return DB_WRITE_ERROR
在此文件中,第 4 行到第 7 行执行所需的导入。以下是其余代码的作用:
-
第 9 到 11 行定义
DEFAULT_DB_FILE_PATH
保存默认数据库文件路径。如果用户不提供自定义路径,应用程序将使用此路径。 -
第 13 到 17 行定义了
get_database_path()
. 此函数将应用程序配置文件的路径作为参数,使用 读取输入文件ConfigParser.read()
,并返回一个Path
对象,该对象表示文件系统上待办事项数据库的路径。该ConfigParser
实例将数据存储在字典中。该"General"
键表示该文件部分,其存储所需的信息。该"database"
键检索数据库路径。 -
第 19 到 25 行定义了
init_database()
. 此函数采用数据库路径并写入一个表示空列表的字符串。您调用.write_text()
数据库路径,该列表使用空的待办事项列表初始化 JSON 数据库。如果进程运行成功,则init_database()
返回SUCCESS
。否则,它返回适当的错误代码。
凉爽的!现在您可以从应用程序的配置文件中检索数据库文件路径。您还可以使用 JSON 格式的空待办事项列表初始化数据库。是时候init
使用 Typer实现该命令,以便您的用户可以从 CLI 初始化他们的待办事项数据库。
实施init
CLI 命令
将您在本节中编写的所有代码放在一起的最后一步是将init
命令添加到应用程序的 CLI。此命令将采用可选的数据库文件路径。然后它会创建应用程序的配置文件和待办事项数据库。
继续并添加init()
到您的cli.py
文件中:
"""This module provides the RP To-Do CLI."""
# rptodo/cli.py
from pathlib import Path
from typing import Optional
import typer
from rptodo import ERRORS, __app_name__, __version__, config, database
app = typer.Typer()
@app.command()
def init(
db_path: str = typer.Option(
str(database.DEFAULT_DB_FILE_PATH),
"--db-path",
"-db",
prompt="to-do database location?",
),
) -> None:
"""Initialize the to-do database."""
app_init_error = config.init_app(db_path)
if app_init_error:
typer.secho(
f'Creating config file failed with "{ERRORS[app_init_error]}"',
fg=typer.colors.RED,
)
raise typer.Exit(1)
db_init_error = database.init_database(Path(db_path))
if db_init_error:
typer.secho(
f'Creating database failed with "{ERRORS[db_init_error]}"',
fg=typer.colors.RED,
)
raise typer.Exit(1)
else:
typer.secho(f"The to-do database is {db_path}", fg=typer.colors.GREEN)
def _version_callback(value: bool) -> None:
# ...
下面是这个新代码的工作原理:
-
第 4 行和第 9 行更新所需的导入。
-
第 13 和 14 行定义
init()
为使用@app.command()
装饰器的 Typer 命令。 -
第 15 到 20 行定义了一个 Typer
Option
实例并将其作为默认值分配给db_path
. 要为此选项提供值,您的用户需要使用--db-path
或-db
后跟数据库路径。该prompt
参数显示询问数据库位置的提示。它还允许您通过按 接受默认路径Enter。 -
第 23 行调用
init_app()
创建应用程序的配置文件和待办事项数据库。 -
第 24 到 29 行检查对 的调用是否
init_app()
返回错误。如果是这样,第 25 到 28 行会打印一条错误消息。第 29 行以typer.Exit
异常和退出代码退出应用程序,1
以表示应用程序因错误而终止。 -
第 30 行调用
init_database()
以空的待办事项列表初始化数据库。 -
第 31 到 38 行检查对 的调用是否
init_database()
返回错误。如果是,则第 32 到 35 行显示错误消息,第 36 行退出应用程序。否则,第 38 行以绿色文本打印成功消息。
要打印此代码中的消息,请使用typer.secho()
. 此函数采用前景参数 ,fg
它允许您在将文本打印到屏幕时使用不同的颜色。Typer 在typer.colors
. 在那里,你会发现RED
,BLUE
,GREEN
,等等。您可以secho()
像这里一样使用这些颜色。
注意:本教程中的代码示例中的行号用于说明目的。大多数情况下,它们与您在最终模块或脚本中的行号不匹配。
好的!有了所有这些代码,您现在可以init
尝试使用该命令。返回终端并运行以下命令:
(venv) $ python -m rptodo init
to-do database location? [/home/user/.user_todo.json]:
The to-do database is /home/user/.user_todo.json
此命令会提示您输入数据库位置。您可以按Enter接受方括号中的默认路径,也可以输入自定义路径,然后按Enter。应用程序创建待办事项数据库并告诉您从现在开始它将驻留在何处。
或者,你可以直接通过提供一个自定义数据库路径init
与-db
或--db-path
选项,然后按所需的路径。在所有情况下,您的自定义路径都应包含数据库文件名。
运行上述命令后,查看您的主目录。您将拥有一个以您使用的文件名命名的 JSON 文件init
。您还将在主文件夹中的某处拥有一个rptodo/
包含config.ini
文件的目录。此文件的特定路径将取决于您当前的操作系统。例如,在 Ubuntu 上,该文件将位于/home/user/.config/rptodo/
.
第 4 步:设置待办事项应用程序后端
到目前为止,您已经创建了一种创建、初始化和连接到待办事项数据库的方法。现在您可以开始考虑您的数据模型了。换句话说,您需要考虑如何表示和存储有关待办事项的数据。您还需要定义您的应用程序将如何处理 CLI 和数据库之间的通信。
您可以通过单击下面的链接并转到source_code_step_4/
目录来下载代码以及将在本节中使用的所有其他资源:
定义单一待办事项
首先,考虑定义单个待办事项所需的数据。在这个项目中,待办事项将包含以下信息:
- 描述:你如何描述这个待办事项?
- 优先级:这个待办事项比其他待办事项有什么优先级?
- 完成:这个待办事项完成了吗?
要存储此信息,您可以使用常规 Python 字典:
todo = {
"Description": "Get some milk.",
"Priority": 2,
"Done": True,
}
该"Description"
密钥存储描述当前的字符串待办事项。该"Priority"
键可以采用三个可能的值:1
高、2
中和3
低优先级。当您完成待办事项或其他情况时,"Done"
关键就成立。True
False
与 CLI 通信
要与 CLI 进行通信,您将使用两个包含所需信息的数据:
todo
: 保存当前待办事项信息的字典error
: 确认当前操作是否成功的返回码或错误码
要存储此数据,您将使用具有适当命名字段的命名元组。打开rptodo.py
模块 fromrptodo
以创建所需的命名元组:
1"""This module provides the RP To-Do model-controller."""
2# rptodo/rptodo.py
3
4from typing import Any, Dict, NamedTuple
5
6class CurrentTodo(NamedTuple):
7 todo: Dict[str, Any]
8 error: int
在 中rptodo.py
,您首先从 中导入一些必需的对象typing
。第6行,你创建的子类typing.NamedTuple
叫CurrentTodo
两个字段todo
和error
。
子类化NamedTuple
允许您创建命名元组,并为其命名字段提供类型提示。例如,todo
上面的字段包含一个键为 typestr
和值为 type的字典Any
。该error
字段包含一个int
值。
与数据库通信
现在您需要另一个数据容器,它允许您向待办事项数据库发送数据并从其中检索数据。在这种情况下,您将使用另一个具有以下字段的命名元组:
todo_list
:您将从数据库中写入和读取的待办事项列表error
: 一个整数,表示与当前数据库操作相关的返回码
最后,您将创建一个类DatabaseHandler
,用于向待办事项数据库读取和写入数据。继续打开database.py
。到达那里后,输入以下代码:
1# rptodo/database.py
2
3import configparser
4import json
5from pathlib import Path
6from typing import Any, Dict, List, NamedTuple
7
8from rptodo import DB_READ_ERROR, DB_WRITE_ERROR, JSON_ERROR, SUCCESS
9
10# ...
11
12class DBResponse(NamedTuple):
13 todo_list: List[Dict[str, Any]]
14 error: int
15
16class DatabaseHandler:
17 def __init__(self, db_path: Path) -> None:
18 self._db_path = db_path
19
20 def read_todos(self) -> DBResponse:
21 try:
22 with self._db_path.open("r") as db:
23 try:
24 return DBResponse(json.load(db), SUCCESS)
25 except json.JSONDecodeError: # Catch wrong JSON format
26 return DBResponse([], JSON_ERROR)
27 except OSError: # Catch file IO problems
28 return DBResponse([], DB_READ_ERROR)
29
30 def write_todos(self, todo_list: List[Dict[str, Any]]) -> DBResponse:
31 try:
32 with self._db_path.open("w") as db:
33 json.dump(todo_list, db, indent=4)
34 return DBResponse(todo_list, SUCCESS)
35 except OSError: # Catch file IO problems
36 return DBResponse(todo_list, DB_WRITE_ERROR)
下面是这段代码的作用:
-
第 4、6 和 8 行添加了一些必需的导入。
-
第 12 到 14 行定义
DBResponse
为一个NamedTuple
子类。该todo_list
字段是代表单个待办事项的字典列表,而该error
字段包含一个整数返回码。 -
第 16 行定义了
DatabaseHandler
,它允许您使用json
标准库中的模块读取和写入数据到待办事项数据库。 -
第 17 行和第 18 行定义了类初始值设定项,它接受一个参数,表示文件系统上数据库的路径。
-
第 20 行定义了
.read_todos()
. 此方法从数据库读取待办事项列表并将其反序列化。 -
第 21 行开始了一个
try
…except
语句来捕获打开数据库时发生的任何错误。如果发生错误,则第 28 行返回一个DBResponse
实例,其中包含一个空的待办事项列表和一个DB_READ_ERROR
. -
第 22 行打开数据库以使用
with
语句进行读取。 -
第 23 行开始另一个
try
…except
语句,以捕获在您从待办事项数据库加载和反序列化 JSON 内容时发生的任何错误。 -
第 24 行返回一个
DBResponse
实例,json.load()
其中包含以待办事项数据库对象作为参数的调用结果。此结果由字典列表组成。每本词典都代表一个待办事项。该error
领域DBResponse
保持SUCCESS
发出信号,表明操作成功。 -
第 25
JSONDecodeError
行在从数据库加载 JSON 内容时捕获 any ,第 26 行返回一个空列表和一个JSON_ERROR
. -
第 27行在加载 JSON 文件时捕获任何文件 IO 问题,第 28 行返回一个
DBResponse
带有空待办事项列表和DB_READ_ERROR
. -
第 30 行定义了
.write_todos()
,它获取待办事项字典列表并将其写入数据库。 -
第 31 行开始了一个
try
…except
语句来捕获打开数据库时发生的任何错误。如果发生错误,则第 36 行返回一个DBResponse
实例,其中包含原始待办事项列表和DB_READ_ERROR
. -
第 32 行使用
with
语句打开数据库进行写入。 -
第 33行将待办事项列表作为 JSON 负载转储到数据库中。
-
第 34 行返回一个包含
DBResponse
待办事项列表和SUCCESS
代码的实例。
哇!那是很多!现在您已完成编码DatabaseHandler
和设置数据交换机制,您可以考虑如何将它们连接到应用程序的 CLI。
编写控制器类, Todoer
要将DatabaseHandler
逻辑与应用程序的 CLI连接起来,您将编写一个名为Todoer
. 此类的工作方式类似于模型-视图-控制器模式中的控制器。
现在返回rptodo.py
并添加以下代码:
# rptodo/rptodo.py
from pathlib import Path
from typing import Any, Dict, NamedTuple
from rptodo.database import DatabaseHandler
# ...
class Todoer:
def __init__(self, db_path: Path) -> None:
self._db_handler = DatabaseHandler(db_path)
此代码包括一些导入和Todoer
. 这个类使用组合,所以它有一个DatabaseHandler
组件来促进与待办事项数据库的直接通信。在接下来的部分中,您将向此类添加更多代码。
在本节中,您将许多设置放在一起,这些设置塑造了待办事项应用程序后端的工作方式。您已经决定使用什么数据结构来存储待办事项数据。您还定义了将使用哪种数据库来保存待办事项信息以及如何对其进行操作。
完成所有这些设置后,您现在可以开始为您的用户提供价值,允许他们填充他们的待办事项列表。您还将实现一种在屏幕上显示待办事项的方法。
编写添加和列出待办事项功能的代码
- 点赞
- 收藏
- 关注作者
评论(0)