python 的框架 dash 开发TodoList Web 应用

TodoList Web 应用

在这里插入图片描述

项目简介

这是一个基于 Dash 和 SQLAlchemy 的现代化 TodoList Web 应用,提供了简单而强大的待办事项管理功能。

主要特性

  • 添加新的待办事项
  • 删除待办事项
  • 标记待办事项为已完成/未完成
  • 分页展示待办事项列表
  • 实时更新和交互

技术栈

  • Python
  • Dash (Web框架)
  • SQLAlchemy (ORM)
  • SQLite (数据库)
  • Dash Bootstrap Components (UI组件)

功能详细说明

待办事项管理

应用提供了一个统一的回调函数 manage_todos(),处理以下交互逻辑:

  1. 删除待办事项
  2. 添加新的待办事项
  3. 切换待办事项状态
  4. 分页展示待办事项列表
删除功能
  • 支持通过删除按钮移除指定的待办事项
  • 添加了详细的错误处理和日志记录
  • 确保只处理有效的点击事件
状态切换
  • 支持多种状态切换方式(复选框和开关)
  • 灵活处理不同类型的状态值
  • 实时更新待办事项完成状态
分页
  • 默认每页显示10个待办事项
  • 动态计算总页数
  • 支持页面间切换

调试与日志

应用内置详细的日志记录机制,记录:

  • 回调上下文详情
  • 触发的输入事件
  • 操作执行情况
  • 错误信息

运行项目

依赖安装

pip install -r requirements.txt

启动应用

python app.py

访问 http://127.0.0.1:8050/ 使用应用

requirements.txt
‘’’
dash2.14.1
dash-bootstrap-components
1.5.0
sqlalchemy2.0.25
plotly
5.19.0

‘’’

import dash
import dash_bootstrap_components as dbc
from dash import html, dcc, Input, Output, State, dash_table
from sqlalchemy import create_engine, Column, Integer, String, Boolean, DateTime
from sqlalchemy.orm import sessionmaker, declarative_base
from sqlalchemy.sql import func
from datetime import datetime
import logging
import json  # 确保导入 json 模块# 配置日志
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s: %(message)s')# 数据库配置
DATABASE_URL = 'sqlite:///todolist.db'
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(bind=engine)
Base = declarative_base()# 待办事项模型
class Todo(Base):__tablename__ = 'todos'id = Column(Integer, primary_key=True, index=True)title = Column(String, index=True)description = Column(String, nullable=True)completed = Column(Boolean, default=False)created_at = Column(DateTime, server_default=func.now())updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())# 创建数据库表
Base.metadata.create_all(bind=engine)# 初始化 Dash 应用
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])def get_todos(page=1, per_page=10):"""获取分页后的待办事项"""db = SessionLocal()try:total_todos = db.query(Todo).count()offset = (page - 1) * per_pagetodos = db.query(Todo).order_by(Todo.created_at.desc()).offset(offset).limit(per_page).all()logging.debug(f"Total todos: {total_todos}, Page: {page}, Per page: {per_page}")return todos, total_todosfinally:db.close()def add_todo(title, description):"""添加新的待办事项"""db = SessionLocal()try:new_todo = Todo(title=title, description=description)db.add(new_todo)db.commit()db.refresh(new_todo)logging.debug(f"Added new todo: {new_todo.title}")return new_todofinally:db.close()def update_todo_status(todo_id, completed):"""更新待办事项状态"""db = SessionLocal()try:todo = db.query(Todo).filter(Todo.id == todo_id).first()if todo:todo.completed = completeddb.commit()logging.debug(f"Todo {todo_id} status updated to {completed}")except Exception as e:logging.error(f"Error updating todo status: {e}")finally:db.close()def delete_todo(todo_id):"""删除待办事项"""db = SessionLocal()try:todo = db.query(Todo).filter(Todo.id == todo_id).first()if todo:db.delete(todo)db.commit()finally:db.close()def render_todo_list(todos):"""渲染待办事项列表"""todo_list = []for todo in todos:todo_list.append(dbc.Card([dbc.CardBody([html.H5(todo.title, className="card-title"),html.P(todo.description or '', className="card-text"),dbc.Checklist(options=[{'label': '已完成', 'value': 1}],value=[1] if todo.completed else [],id={'type': 'todo-status', 'index': todo.id},switch=True),dbc.Button("删除", color="danger", size="sm", id={'type': 'delete-todo', 'index': todo.id})])], className="mb-2", id=f'todo-card-{todo.id}'))return todo_list# 应用布局
app.layout = dbc.Container([html.H1("TodoList 应用", className="text-center my-4"),# 添加待办事项表单dbc.Row([dbc.Col([dbc.Label("标题"),dbc.Input(id='todo-title', type='text', placeholder='输入待办事项标题')], width=12),], className="mb-3"),dbc.Row([dbc.Col([dbc.Label("描述"),dbc.Input(id='todo-description', type='text', placeholder='输入待办事项描述')], width=12)], className="mb-3"),dbc.Row([dbc.Col([dbc.Button("添加待办", id='add-todo-button', color='primary')])], className="mb-3"),# 待办事项列表html.Div(id='todo-list-container'),# 分页组件dbc.Pagination(id='todo-pagination',max_value=1,  # 初始化为1fully_expanded=False),# 调试信息显示html.Div(id='debug-output')
], fluid=True)# 初始化加载待办事项
@app.callback([Output('todo-list-container', 'children'),Output('todo-pagination', 'max_value')],[Input('todo-pagination', 'active_page')]
)
def initial_load(active_page):"""初始加载待办事项"""page = active_page or 1per_page = 10todos, total_todos = get_todos(page, per_page)# 计算总页数total_pages = max(1, (total_todos + per_page - 1) // per_page)# 渲染待办事项列表todo_list = render_todo_list(todos)return [todo_list, total_pages]@app.callback([Output('todo-list-container', 'children', allow_duplicate=True),Output('todo-pagination', 'max_value', allow_duplicate=True),Output('todo-title', 'value'),Output('todo-description', 'value'),Output('debug-output', 'children')],[Input('todo-pagination', 'active_page'),Input('add-todo-button', 'n_clicks'),Input({'type': 'delete-todo', 'index': dash.ALL}, 'n_clicks'),Input({'type': 'todo-status', 'index': dash.ALL}, 'value')],[State('todo-title', 'value'),State('todo-description', 'value'),State({'type': 'delete-todo', 'index': dash.ALL}, 'id'),State({'type': 'todo-status', 'index': dash.ALL}, 'id')],prevent_initial_call=True
)
def manage_todos(active_page, add_clicks, delete_clicks, status_values, title, description, delete_ids, status_ids):"""统一管理待办事项的增删改查操作这个回调函数处理所有的交互逻辑:1. 删除待办事项2. 添加新的待办事项3. 切换待办事项状态4. 分页展示待办事项列表参数说明:- active_page: 当前分页页码- add_clicks: 添加按钮点击次数- delete_clicks: 删除按钮点击次数列表- status_values: 状态切换值列表- title, description: 新建待办事项的标题和描述- delete_ids, status_ids: 对应的待办事项ID"""ctx = dash.callback_context# 记录详细的调试日志,帮助追踪回调上下文logging.debug("Callback Context Details:")logging.debug(f"Triggered Inputs: {ctx.triggered}")logging.debug(f"Input Values:")logging.debug(f"Active Page: {active_page}")logging.debug(f"Add Clicks: {add_clicks}")logging.debug(f"Delete Clicks: {delete_clicks}")logging.debug(f"Delete IDs: {delete_ids}")logging.debug(f"Status Values: {status_values}")logging.debug(f"Status IDs: {status_ids}")# 初始加载:如果没有触发任何事件,默认加载第一页if not ctx.triggered:page = 1per_page = 10todos, total_todos = get_todos(page, per_page)total_pages = max(1, (total_todos + per_page - 1) // per_page)todo_list = render_todo_list(todos)return [todo_list, total_pages, title, description, '']# 初始化调试消息triggered = ctx.triggereddebug_message = "Triggered Inputs:\n"# 处理删除待办事项for n_clicks, delete_id in zip(delete_clicks, delete_ids):logging.debug(f"Delete: n_clicks={n_clicks}, delete_id={delete_id}")# 确保是有效的点击事件(非初始 None 值)if n_clicks is not None and n_clicks > 0:todo_id = delete_id['index']logging.debug(f"Attempting to delete todo with ID: {todo_id}")try:# 执行删除操作delete_todo(todo_id)debug_message += f"Deleted todo with ID: {todo_id}\n"except Exception as e:# 记录删除错误logging.error(f"Error deleting todo {todo_id}: {e}")debug_message += f"Failed to delete todo {todo_id}: {e}\n"# 处理添加新的待办事项if add_clicks and title:# 创建新的待办事项add_todo(title, description or '')# 清空输入框title = Nonedescription = None# 处理待办事项状态切换for value, status_id in zip(status_values, status_ids):todo_id = status_id['index']# 灵活处理不同类型的状态值if isinstance(value, list):completed = 1 in value  # 对于复选框else:completed = bool(value)  # 对于开关logging.debug(f"Updating todo {todo_id} status to {completed}")# 更新待办事项状态update_todo_status(todo_id, completed)debug_message += f"Updated todo {todo_id} status to {completed}\n"# 获取当前页的待办事项page = active_page or 1per_page = 10todos, total_todos = get_todos(page, per_page)# 计算总页数total_pages = max(1, (total_todos + per_page - 1) // per_page)debug_message += f"Total todos: {total_todos}, Total pages: {total_pages}\n"# 渲染待办事项列表todo_list = render_todo_list(todos)# 返回更新后的组件状态return [todo_list, total_pages, title, description, debug_message]if __name__ == '__main__':app.run_server(debug=True)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/17986.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

tenda路由器WriteFacMac存在远程命令执行漏洞(CVE-2024-10697)

一、漏洞简介 tenda路由器WriteFacMac存在远程命令执行漏洞 二、漏洞影响 tenda路由器三、网络测绘: fofa: title"Tenda | LOGIN"四、复现过程 POC 1 GET /goform/WriteFacMac?macls%20%3E/webroot/1.txt HTTP/1.1 Accept: text/html,application/…

无需编码5分钟免费部署云上调用满血版DeepSeek

大家好,我是 V 哥。如何自己部署DeepSeek调用满血版。首先,如果你遇到了使用公共服务器时的延迟或限制,想要本地部署以获得更好的性能和稳定性。你是不是也想自己来部署DeepSeek呢,其实除了自己部署本地DeepSeek,还可以…

linux笔记3----防火墙(ubuntu)

防火墙管理工具 ubuntu里使用ufw来管理防火墙。ufw是一个管理防火墙规则的前端工具。本文阐述如何开启、关闭防火墙,放行指定端口。 因为我采用putty远程来使用,需要关闭防火墙或者放行22端口。 核心思维 因为ufw只是一个前端工具,所以一开…

【音视频】RTSP拉流: RTP负载AAC详解(三)

此文为系列文章,此系列主要讲解RTSP客户端的拉流及播放,文章持续更新,会从rtsp的基本协议讲起,如何一步步实现音视频的拉流过程,包括一系列涉及到的协议,rtsp,sdp, rtp(本…

若依系统环境搭建记录

开源若依系统网上资料也很全的,本篇博文记录下自己搭建环境过程中遇到的一些问题。 配置Maven和编辑器选择 我懒得配置Eclipse了,直接用vscode作为编辑器,后面构建运行都用命令行。 配置数据库连接 按照mysql5.7按网上教程即可&#xff1…

【MySql】应用系统等保测评MySQL服务器相关策略设置以及最终验证,MySQL安全策略设置以及最终验证

文章目录 一、概要二、环境及实现三、前期准备四、操作步骤1、所有的数据库需要设置三权账户:系统管理员、网络管理员和安全管理员创建系统管理员账户:创建网络管理员账户:创建安全管理员账户: 2、所有数据库密码的负责度策略需要…

bootplus管理系统 file/download 任意文件下载漏洞

bootplus管理系统 file/download 任意文件下载漏洞 漏洞描述 bootplus是基于SpringBoot + Shiro + MyBatisPlus的,拥有接口管理,权限管理,监控组件等功能的一体化权限管理框架。该项目中的file/download接口存在任意文件下载漏洞, 攻击者可以通过该漏洞下载查看目标系统的…

《open3d qt 网格采样成点云》

open3d qt 网格采样成点云 效果展示二、流程三、代码效果展示 二、流程 创建动作,链接到槽函数,并把动作放置菜单栏 参照前文 三、代码 1、槽函数实现 void on_actionMeshUniformSample_triggered();//均匀采样 void MainWindow::

部署 DeepSeek R1各个版本所需硬件配置清单

DeepSeek-R1 通过其卓越的推理性能和灵活的训练机制,在 2025 年的春节期间受到了广泛关注。 DeepSeek-R1 是一款高性能的 AI 推理模型,主要通过强化学习技术来增强模型在复杂任务场景下的推理能力。 在本地部署 DeepSeek-R1 时,尤其是完整的…

hive高频写入小数据,导致hdfs小文件过多,出现查询效率很低的情况

问题描述 hive高频写入小数据,导致hdfs小文件过多,出现查询效率很低的情况分析过程 先复现现象 select count() from ads.ads_sdd_flow_managemlt_to_ids_mm;–15分钟,小文件10983 select max(mm) from ads.ads_sdd_flow_managemlt_to_ids…

git用法(简易版)

介绍 git是一个版本管理工具 使用方法 建立仓库 第一步 git init:初始化仓库 第二步 git add .:将代码添加到暂存区 第三步 git commit -m "first":为修改添加备注 第四步 git remote add origin 你的url 第五步 git pus…

顺序表SeqList(c语言)(动态顺序表)

前言: 顺序表是一种数据结构,是内存中存储数据的一种方式,他的内存连续性使得它有较高的缓存利用率,它在内存中广泛使用,比如数组,就是典型的顺序表。 实现思路: 一般是建立三个文件&#xf…

DeepSeek介绍本地部署保姆级教程

2025年春节前后,DeepSeek 如滚烫油锅中溅入的一碗水,瞬间激起千层浪,在网络世界里掀起了一场热议风暴,迅速火遍大江南北。无论是互联网行业的前沿先锋,还是传统行业的资深从业者;无论是专注于开发、测试、运…

Bash 中的运算方式

目录 概述: 1. (()) 运算符 2. let 命令 3. expr 命令 4. $[] 直接运算 5. bc(计算器,支持浮点数) 6. awk(强大的文本处理工具,也可计算) 概述: Bash 本身只支持整数运算&am…

主动视觉可能就是你所需要的:在双臂机器人操作中探索主动视觉

AV-ALOHA 系统使用用于 AV 的 VR 耳机实现直观的数据收集,并且 用于作的 VR 控制器或引线臂。这有助于捕捉全身和头部 远程作我们的真实和模拟系统的运动,记录来自 6 个的视频 不同的摄像头,并为我们的 AV 仿制学习策略提供训练数据。 加州大…

centos7 nexus3.77 搭建

1.确保安装了JDK sudo yum install -y java-17-openjdk java-17-openjdk-devel java -version 2.下载Nexus最新版 官网地址:Sonatype Nexus Repository Manager Community Edition | Download csdn下载:https://download.csdn.net/download/supercrsky/90384049 上传到nex…

html 点击弹出视频弹窗

一、效果: 点击视频按钮后,弹出弹窗 播放视频 二、代码 <div class="index_change_video" data-video-src="</

10. Hbase Compaction命令

一. 什么是Compaction 在 HBase 中&#xff0c;频繁进行数据插入、更新和删除操作会生成许多小的 HFile&#xff0c;当 HFile 数量增多时&#xff0c;会影响HBase的读写性能。此外&#xff0c;垃圾数据的存在也会增加存储需求。因此&#xff0c;定期进行 Compact操作&#xff…

DeepSeek R1打造本地化RAG知识库

本文将详细介绍如何使用Ollama、Deepseek R1大语音模型、Nomic-Embed-Text向量模型和AnythingLLM共同搭建一个本地的私有RAG知识库。 一. 准备工作 什么是RAG&#xff1f; RAG是一种结合了信息检索和大模型&#xff08;LLM&#xff09;的技术&#xff0c;在对抗大模型幻觉、…

Kafka分区管理大师指南:扩容、均衡、迁移与限流全解析

#作者&#xff1a;孙德新 文章目录 分区分配操作(kafka-reassign-partitions.sh)1.1 分区扩容、数据均衡、迁移(kafka-reassign-partitions.sh)1.2、修改topic分区partition的副本数&#xff08;扩缩容副本&#xff09;1.3、Partition Reassign场景限流1.4、节点内副本移动到不…