您好,登录后才能下订单哦!
在现代软件开发中,构建一个功能完善且用户友好的应用程序是非常重要的。Python作为一种广泛使用的编程语言,提供了丰富的库和工具来简化开发过程。本文将介绍如何使用Python中的Rich库和TinyDB来构建一个联系人通讯录应用程序。通过本文,你将学习如何利用Rich库来美化命令行界面,以及如何使用TinyDB来存储和管理联系人数据。
本项目旨在构建一个命令行界面的联系人通讯录应用程序。该应用程序将允许用户执行以下操作:
为了实现这些功能,我们将使用Rich库来美化命令行界面,并使用TinyDB来存储联系人数据。
在开始项目之前,我们需要确保我们的开发环境中安装了所需的库。我们将使用pip
来安装这些库。
pip install rich tinydb
Rich是一个Python库,用于在终端中创建美观的文本输出。它支持多种功能,包括彩色文本、表格、进度条、语法高亮等。Rich库的主要特点包括:
在本项目中,我们将使用Rich库来美化命令行界面,使联系人通讯录应用程序更加用户友好。
TinyDB是一个轻量级的NoSQL数据库,适用于小型应用程序。它使用JSON文件来存储数据,并且具有简单的API,易于使用。TinyDB的主要特点包括:
在本项目中,我们将使用TinyDB来存储和管理联系人数据。
在开始编写代码之前,我们需要规划项目的结构。以下是我们将使用的项目结构:
contact_book/
│
├── contact_book/
│ ├── __init__.py
│ ├── models.py
│ ├── database.py
│ ├── ui.py
│ ├── commands.py
│ ├── utils.py
│ └── tests/
│ ├── __init__.py
│ ├── test_models.py
│ ├── test_database.py
│ ├── test_ui.py
│ └── test_commands.py
│
├── main.py
├── requirements.txt
└── README.md
contact_book/
:项目的根目录。contact_book/contact_book/
:包含项目的主要代码。
__init__.py
:使目录成为一个Python包。models.py
:定义联系人模型。database.py
:处理与TinyDB的交互。ui.py
:处理命令行界面的显示。commands.py
:实现各种命令(如添加、删除、更新联系人等)。utils.py
:包含一些实用函数。tests/
:包含单元测试。main.py
:项目的入口点。requirements.txt
:列出项目所需的依赖项。README.md
:项目的说明文档。首先,我们需要定义一个联系人模型。联系人模型将包含以下字段:
id
:唯一标识符。name
:联系人姓名。phone
:联系人电话。email
:联系人电子邮件。address
:联系人地址。我们将使用Python的dataclasses
模块来定义联系人模型。
# contact_book/models.py
from dataclasses import dataclass
from typing import Optional
@dataclass
class Contact:
id: int
name: str
phone: str
email: Optional[str] = None
address: Optional[str] = None
接下来,我们需要实现与TinyDB的交互。我们将创建一个Database
类来封装与TinyDB的交互。
# contact_book/database.py
from tinydb import TinyDB, Query
class Database:
def __init__(self, db_path: str = 'contacts.json'):
self.db = TinyDB(db_path)
self.contacts_table = self.db.table('contacts')
def add_contact(self, contact: 'Contact') -> int:
return self.contacts_table.insert(contact.__dict__)
def get_contact(self, contact_id: int) -> dict:
return self.contacts_table.get(doc_id=contact_id)
def get_all_contacts(self) -> list:
return self.contacts_table.all()
def update_contact(self, contact_id: int, contact: 'Contact') -> None:
self.contacts_table.update(contact.__dict__, doc_ids=[contact_id])
def delete_contact(self, contact_id: int) -> None:
self.contacts_table.remove(doc_ids=[contact_id])
def search_contacts(self, query: str) -> list:
ContactQuery = Query()
return self.contacts_table.search(
(ContactQuery.name.search(query)) |
(ContactQuery.phone.search(query)) |
(ContactQuery.email.search(query)) |
(ContactQuery.address.search(query))
)
现在,我们将使用Rich库来美化命令行界面。我们将创建一个UI
类来处理界面的显示。
# contact_book/ui.py
from rich.console import Console
from rich.table import Table
class UI:
def __init__(self):
self.console = Console()
def display_contacts(self, contacts: list) -> None:
table = Table(title="Contacts")
table.add_column("ID", justify="right", style="cyan", no_wrap=True)
table.add_column("Name", style="magenta")
table.add_column("Phone", style="green")
table.add_column("Email", style="blue")
table.add_column("Address", style="yellow")
for contact in contacts:
table.add_row(
str(contact['id']),
contact['name'],
contact['phone'],
contact.get('email', ''),
contact.get('address', '')
)
self.console.print(table)
def display_message(self, message: str, style: str = "bold green") -> None:
self.console.print(message, style=style)
def display_error(self, message: str) -> None:
self.console.print(f"[bold red]Error: {message}[/bold red]")
接下来,我们将实现添加、删除、更新和查看联系人的功能。我们将创建一个Commands
类来封装这些功能。
# contact_book/commands.py
from typing import Optional
from .models import Contact
from .database import Database
from .ui import UI
class Commands:
def __init__(self):
self.db = Database()
self.ui = UI()
def add_contact(self, name: str, phone: str, email: Optional[str] = None, address: Optional[str] = None) -> None:
contact = Contact(id=self._generate_id(), name=name, phone=phone, email=email, address=address)
self.db.add_contact(contact)
self.ui.display_message("Contact added successfully!")
def delete_contact(self, contact_id: int) -> None:
if self.db.get_contact(contact_id):
self.db.delete_contact(contact_id)
self.ui.display_message("Contact deleted successfully!")
else:
self.ui.display_error("Contact not found!")
def update_contact(self, contact_id: int, name: Optional[str] = None, phone: Optional[str] = None, email: Optional[str] = None, address: Optional[str] = None) -> None:
contact = self.db.get_contact(contact_id)
if contact:
updated_contact = Contact(
id=contact_id,
name=name if name else contact['name'],
phone=phone if phone else contact['phone'],
email=email if email else contact.get('email'),
address=address if address else contact.get('address')
)
self.db.update_contact(contact_id, updated_contact)
self.ui.display_message("Contact updated successfully!")
else:
self.ui.display_error("Contact not found!")
def list_contacts(self) -> None:
contacts = self.db.get_all_contacts()
self.ui.display_contacts(contacts)
def _generate_id(self) -> int:
contacts = self.db.get_all_contacts()
return max([contact['id'] for contact in contacts], default=0) + 1
为了增强应用程序的功能,我们将添加一个搜索功能,允许用户根据姓名、电话、电子邮件或地址搜索联系人。
# contact_book/commands.py
class Commands:
# ... (之前的代码)
def search_contacts(self, query: str) -> None:
contacts = self.db.search_contacts(query)
if contacts:
self.ui.display_contacts(contacts)
else:
self.ui.display_message("No contacts found.")
当联系人数量较多时,我们需要添加分页功能,以便用户可以分页查看联系人列表。
# contact_book/commands.py
class Commands:
# ... (之前的代码)
def list_contacts(self, page: int = 1, page_size: int = 10) -> None:
contacts = self.db.get_all_contacts()
start = (page - 1) * page_size
end = start + page_size
paginated_contacts = contacts[start:end]
self.ui.display_contacts(paginated_contacts)
为了方便用户备份联系人数据,我们将添加一个导出功能,允许用户将联系人数据导出为CSV文件。
# contact_book/commands.py
import csv
class Commands:
# ... (之前的代码)
def export_contacts(self, file_path: str) -> None:
contacts = self.db.get_all_contacts()
with open(file_path, mode='w', newline='') as file:
writer = csv.DictWriter(file, fieldnames=['id', 'name', 'phone', 'email', 'address'])
writer.writeheader()
writer.writerows(contacts)
self.ui.display_message(f"Contacts exported to {file_path} successfully!")
为了允许用户从CSV文件导入联系人数据,我们将添加一个导入功能。
# contact_book/commands.py
class Commands:
# ... (之前的代码)
def import_contacts(self, file_path: str) -> None:
try:
with open(file_path, mode='r') as file:
reader = csv.DictReader(file)
for row in reader:
contact = Contact(
id=int(row['id']),
name=row['name'],
phone=row['phone'],
email=row.get('email'),
address=row.get('address')
)
self.db.add_contact(contact)
self.ui.display_message(f"Contacts imported from {file_path} successfully!")
except Exception as e:
self.ui.display_error(f"Failed to import contacts: {e}")
为了确保数据安全,我们将添加一个备份功能,允许用户备份联系人数据。
# contact_book/commands.py
import shutil
class Commands:
# ... (之前的代码)
def backup_contacts(self, backup_path: str) -> None:
try:
shutil.copy2('contacts.json', backup_path)
self.ui.display_message(f"Contacts backed up to {backup_path} successfully!")
except Exception as e:
self.ui.display_error(f"Failed to backup contacts: {e}")
为了允许用户从备份中恢复联系人数据,我们将添加一个恢复功能。
# contact_book/commands.py
class Commands:
# ... (之前的代码)
def restore_contacts(self, backup_path: str) -> None:
try:
shutil.copy2(backup_path, 'contacts.json')
self.ui.display_message(f"Contacts restored from {backup_path} successfully!")
except Exception as e:
self.ui.display_error(f"Failed to restore contacts: {e}")
为了帮助调试和监控应用程序的运行状态,我们将添加一个日志功能。
# contact_book/utils.py
import logging
def setup_logger(log_file: str = 'contact_book.log') -> logging.Logger:
logger = logging.getLogger('contact_book')
logger.setLevel(logging.DEBUG)
file_handler = logging.FileHandler(log_file)
file_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
return logger
在commands.py
中使用日志功能:
# contact_book/commands.py
from .utils import setup_logger
class Commands:
def __init__(self):
self.db = Database()
self.ui = UI()
self.logger = setup_logger()
def add_contact(self, name: str, phone: str, email: Optional[str] = None, address: Optional[str] = None) -> None:
try:
contact = Contact(id=self._generate_id(), name=name, phone=phone, email=email, address=address)
self.db.add_contact(contact)
self.ui.display_message("Contact added successfully!")
self.logger.info(f"Added contact: {contact}")
except Exception as e:
self.ui.display_error(f"Failed to add contact: {e}")
self.logger.error(f"Failed to add contact: {e}")
为了增强应用程序的健壮性,我们将添加错误处理机制。
# contact_book/commands.py
class Commands:
# ... (之前的代码)
def delete_contact(self, contact_id: int) -> None:
try:
if self.db.get_contact(contact_id):
self.db.delete_contact(contact_id)
self.ui.display_message("Contact deleted successfully!")
self.logger.info(f"Deleted contact with ID: {contact_id}")
else:
self.ui.display_error("Contact not found!")
self.logger.warning(f"Contact not found with ID: {contact_id}")
except Exception as e:
self.ui.display_error(f"Failed to delete contact: {e}")
self.logger.error(f"Failed to delete contact: {e}")
为了确保代码的正确性,我们将添加单元测试。我们将使用unittest
框架来编写测试。
# contact_book/tests/test_models.py
import unittest
from contact_book.models import Contact
class TestContactModel(unittest.TestCase):
def test_contact_creation(self):
contact = Contact(id=1, name="John Doe", phone="1234567890", email="john@example.com", address="123 Main St")
self.assertEqual(contact.id, 1)
self.assertEqual(contact.name, "John Doe")
self.assertEqual(contact.phone, "1234567890")
self.assertEqual(contact.email, "john@example.com")
self.assertEqual(contact.address, "123 Main St")
if __name__ == '__main__':
unittest.main()
# contact_book/tests/test_database.py
import unittest
from contact_book.database import Database
from contact_book.models import Contact
class TestDatabase(unittest.TestCase):
def setUp(self):
self.db = Database('test_contacts.json')
self.contact = Contact(id=1, name="John Doe", phone="1234567890", email="john@example.com", address="123 Main St")
def test_add_contact(self):
contact_id = self.db.add_contact(self.contact)
self.assertIsNotNone(contact_id)
def test_get_contact(self):
contact_id = self.db.add_contact(self.contact)
contact = self.db.get_contact(contact_id)
self.assertEqual(contact['name'], "John Doe")
def tearDown(self):
import os
if os.path.exists('test_contacts.json'):
os.remove('test_contacts.json')
if __name__ == '__main__':
unittest.main()
通过本文,我们学习了如何使用Python中的Rich库和TinyDB来构建一个功能完善且用户友好的联系人通讯录应用程序。我们实现了添加、删除、更新、查看、搜索、分页、导出、导入、备份、恢复等功能,并添加了日志和错误处理机制。此外,我们还编写了单元测试来确保代码的正确性。
希望本文对你有所帮助,并激发你进一步探索Python编程的兴趣。Happy coding!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。