当前位置: 首页 > news >正文

用Python Streamlit sqlite3 写一个简单博客

图片:

依赖:

streamlit

pandas

matplotlib

代码blog_app.py:

import streamlit as st
import sqlite3
import pandas as pd
from datetime import datetime
import os# 确保中文正常显示# 数据库初始化函数
def init_db():conn = sqlite3.connect('blog.db')c = conn.cursor()# 创建博客文章表c.execute('''CREATE TABLE IF NOT EXISTS posts (id INTEGER PRIMARY KEY AUTOINCREMENT,title TEXT NOT NULL,content TEXT NOT NULL,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,category TEXT,tags TEXT)''')conn.commit()conn.close()# 添加新博客文章
def add_post(title, content, category='未分类', tags=''):conn = sqlite3.connect('blog.db')c = conn.cursor()c.execute('''INSERT INTO posts (title, content, category, tags) VALUES (?, ?, ?, ?)''', (title, content, category, tags))conn.commit()conn.close()# 获取所有博客文章
def get_all_posts():conn = sqlite3.connect('blog.db')# 使用pandas读取数据,确保中文正常显示posts = pd.read_sql_query('SELECT * FROM posts ORDER BY created_at DESC', conn)conn.close()return posts# 获取单篇博客文章
def get_post(post_id):conn = sqlite3.connect('blog.db')c = conn.cursor()c.execute('SELECT * FROM posts WHERE id = ?', (post_id,))post = c.fetchone()conn.close()return post# 更新博客文章
def update_post(post_id, title, content, category, tags):conn = sqlite3.connect('blog.db')c = conn.cursor()c.execute('''UPDATE posts SET title = ?, content = ?, category = ?, tags = ? WHERE id = ?''', (title, content, category, tags, post_id))conn.commit()conn.close()# 删除博客文章
def delete_post(post_id):conn = sqlite3.connect('blog.db')c = conn.cursor()c.execute('DELETE FROM posts WHERE id = ?', (post_id,))conn.commit()conn.close()# 获取分类统计
def get_category_stats():conn = sqlite3.connect('blog.db')stats = pd.read_sql_query('SELECT category, COUNT(*) as count FROM posts GROUP BY category', conn)conn.close()return stats# 主应用函数
def main():# 初始化数据库init_db()st.title('我的博客')# 创建侧边栏导航menu = ['首页', '写文章', '管理文章', '统计']choice = st.sidebar.selectbox('选择功能', menu)if choice == '首页':st.subheader('博客文章')# 显示分类筛选categories = pd.read_sql_query('SELECT DISTINCT category FROM posts', sqlite3.connect('blog.db'))['category'].tolist()categories.insert(0, '全部')selected_category = st.selectbox('按分类筛选', categories)# 获取并显示文章列表if selected_category == '全部':posts = get_all_posts()else:conn = sqlite3.connect('blog.db')posts = pd.read_sql_query('SELECT * FROM posts WHERE category = ? ORDER BY created_at DESC', conn, params=(selected_category,))conn.close()if not posts.empty:for _, post in posts.iterrows():# 使用expander折叠显示文章内容with st.expander(f"{post['title']} ({post['created_at']})"):st.write(f"**分类:** {post['category']}")if post['tags']:st.write(f"**标签:** {post['tags']}")st.write(post['content'])else:st.info('暂无博客文章')elif choice == '写文章':st.subheader('写新文章')with st.form(key='post_form'):title = st.text_input('标题')category = st.text_input('分类', '未分类')tags = st.text_input('标签(用逗号分隔)')content = st.text_area('内容', height=300)submit_button = st.form_submit_button(label='发布文章')if submit_button:if title and content:add_post(title, content, category, tags)st.success('文章发布成功!')else:st.error('请填写标题和内容')elif choice == '管理文章':st.subheader('管理文章')# 显示所有文章进行管理posts = get_all_posts()if not posts.empty:# 创建一个下拉框让用户选择要编辑/删除的文章post_options = {f"{post['title']} ({post['id']})": post['id'] for _, post in posts.iterrows()}selected_post_title = st.selectbox('选择文章', list(post_options.keys()))if selected_post_title:post_id = post_options[selected_post_title]post = get_post(post_id)if post:# 显示文章信息st.write(f"**ID:** {post[0]}")st.write(f"**创建时间:** {post[3]}")# 编辑表单with st.form(key='edit_form'):new_title = st.text_input('标题', post[1])new_category = st.text_input('分类', post[4])new_tags = st.text_input('标签', post[5])new_content = st.text_area('内容', post[2], height=300)col1, col2 = st.columns(2)with col1:update_button = st.form_submit_button(label='更新文章')with col2:delete_button = st.form_submit_button(label='删除文章', type='primary')# 处理表单提交if update_button:if new_title and new_content:update_post(post_id, new_title, new_content, new_category, new_tags)st.success('文章更新成功!')st.experimental_rerun()else:st.error('请填写标题和内容')if delete_button:delete_post(post_id)st.success('文章删除成功!')st.experimental_rerun()else:st.info('暂无文章可管理')elif choice == '统计':st.subheader('博客统计')# 显示文章总数posts = get_all_posts()st.write(f"**文章总数:** {len(posts)}")# 显示分类统计图表try:import matplotlib.pyplot as pltplt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号stats = get_category_stats()if not stats.empty:st.write('**分类统计:**')fig, ax = plt.subplots()stats.plot.pie(y='count', labels=stats['category'], autopct='%1.1f%%', ax=ax)ax.set_ylabel('')st.pyplot(fig)else:st.info('暂无统计数据')except Exception as e:st.error(f'生成统计图表时出错: {e}')if __name__ == '__main__':main()

运行:

streamlit run blog_app.py

http://www.dtcms.com/a/515214.html

相关文章:

  • 微型计算机接口与原理笔记
  • 大学生免费ppt网站广州分销商城开发
  • 良策金宝AI定制方案:构建企业专属的“工程智能体”
  • docker 容器web站点 中文文件名访问404问题
  • 【第五章:计算机视觉-项目实战之推荐/广告系统】2.粗排算法-(1)粗排用来干什么?“我大体筛一下“
  • FDAbench-Full 数据代理任务基准:Python 使用路径
  • HarmonyOS之启动应用内的UIAbility组件
  • 【开题答辩全过程】以抖音热点与可视化分析为例,包含答辩的问题和答案
  • SONiC控制面 + VPP数据面:AsterNOS-VPP的高性能开放之路
  • 未来之窗昭和仙君(二十八)商业收银开发音频播放——东方仙盟筑基期
  • 自助网站系统上海网站建设公司网站建设
  • 杭州网站设计推荐柚米莆田做外贸网站
  • Rust 枚举类详解
  • UU远程——让工作、学习、娱乐跨设备无缝衔接,“远程”更像“身边”
  • 关于模型结构与参数的文件类型及运行设备
  • 一种基于STL-LSTM混合模型的低轨卫星钟差短期预报方法
  • 【Docker】[特殊字符] Docker 部署完全指南 - 从本地开发到云服务器
  • 宝塔面板部署Django:使用Unix Socket套接字通信的完整教程(附核心配置与问题排查)
  • 广西建设局建设行政主管部网站资源网站优化排名软件公司
  • 基于Vue的2025年哈尔滨亚冬会志愿者管理系统5zqg6m36(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • 软件可用性测试历史概念✅软件可用性测试的国际标准✅软件可用性测试方法
  • 深入 JavaScript 对象与代理模式的本质、应用与区别!
  • 响水网站制作公司平顺网站建设
  • 顺昌网站建设临沂网站制作公司
  • Llama-2-7b 昇腾 NPU 测评总结:核心性能数据、场景适配建议与硬件选型参考
  • 奥威BI:AI数据分析赋能企业智能决策
  • Python机器学习与数据分析教程之pandas
  • 【性能】android 启动丢帧分析全攻略
  • 个人网站免费域名注册海报设计网站官网
  • Linux定制篇-Nacos的安装和配置