news 2026/7/15 13:28:11

Python实践学习笔记-带娃编程之——简易个人日记本 - Dairys Demo

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python实践学习笔记-带娃编程之——简易个人日记本 - Dairys Demo

【导航台账】老蒋的技术博客全系列文章汇总(持续更新)

下面是一个简单的个人日记本程序,使用Python和Tkinter GUI库实现。这个程序适合作为我带女儿的第一个真正具有一定的实践价值的编程项目。

使用说明首次使用时,需要先注册账户(点击"注册新账户"按钮),注册时需要输入两次密码确认。

登录后可以选择日期查看和编辑日记,点击"今天"按钮可以快速跳转到当前日期;点击"保存"按钮保存日记内容;点击"清空"按钮可以清空当前日记内容;

点击"退出"按钮可以返回登录界面

功能概述

包括一下四个模块:

1、用户登录(简单验证) 提供用户的注册登录,并加密明文,保存密文,用文件方式存储在服务器中。

2、日历选择日期 提供日历导航功能,点击对应的日期,可以导入(查询)当日的日记。如果不存在则可以写日期,编辑保存。

3、查看和编辑每日日记 结合2的功能,进行查看和编辑。

4、保存日记内容 保存日记内容,demo功能存储在本地,按照json 格式存储,后期在一步一步进行扩展。

项目结构p_diaries/ ├── app.py # 主程序 ├── data/ # 数据存储目录 │ ├── users.json # 用户数据 │ └── diaries/ # 日记存储目录 ├── templates/ # 模板文件 │ ├── base.html │ ├── login.html │ ├── register.html │ ├── diary.html │ └── calendar.html └── static/ └── style.css # 样式文件

核心代码如下:

app.py

""" 功能介绍: 首次使用时,需要先注册账户(点击"注册新账户"按钮) 注册时需要输入两次密码确认 登录后可以选择日期查看和编辑日记 点击"今天"按钮可以快速跳转到当前日期 点击"保存"按钮保存日记内容 点击"清空"按钮可以清空当前日记内容 点击"退出"按钮可以返回登录界面 作者:jay21 创建时间:2025年10月1日 20点58分 """ from flask import Flask, render_template, request, redirect, url_for, session, flash, jsonify import json import os from datetime import datetime, date import hashlib app = Flask(__name__) app.secret_key = 'your_secret_key_here' # 生产环境请更换更安全的密钥 # 数据文件路径 DATA_DIR = 'data' USERS_FILE = os.path.join(DATA_DIR, 'users.json') DIARIES_DIR = os.path.join(DATA_DIR, 'diaries') def init_data_dir(): """初始化数据目录""" if not os.path.exists(DATA_DIR): os.makedirs(DATA_DIR) if not os.path.exists(DIARIES_DIR): os.makedirs(DIARIES_DIR) if not os.path.exists(USERS_FILE): with open(USERS_FILE, 'w', encoding='utf-8') as f: json.dump({}, f, ensure_ascii=False, indent=2) def hash_password(password): """密码哈希函数""" return hashlib.sha256(password.encode()).hexdigest() def load_users(): """加载用户数据""" try: with open(USERS_FILE, 'r', encoding='utf-8') as f: return json.load(f) except (FileNotFoundError, json.JSONDecodeError): return {} def save_users(users): """保存用户数据""" with open(USERS_FILE, 'w', encoding='utf-8') as f: json.dump(users, f, ensure_ascii=False, indent=2) def get_user_diary_file(username): """获取用户的日记文件路径""" return os.path.join(DIARIES_DIR, f"{username}.json") def load_user_diaries(username): """加载用户的日记数据""" diary_file = get_user_diary_file(username) try: with open(diary_file, 'r', encoding='utf-8') as f: return json.load(f) except (FileNotFoundError, json.JSONDecodeError): return {} def save_user_diaries(username, diaries): """保存用户的日记数据""" diary_file = get_user_diary_file(username) with open(diary_file, 'w', encoding='utf-8') as f: json.dump(diaries, f, ensure_ascii=False, indent=2) def login_required(f): """登录装饰器""" from functools import wraps @wraps(f) def decorated_function(*args, **kwargs): if 'username' not in session: return redirect(url_for('login')) return f(*args, **kwargs) return decorated_function @app.route('/') def index(): """首页""" if 'username' in session: return redirect(url_for('diary')) return redirect(url_for('login')) @app.route('/login', methods=['GET', 'POST']) def login(): """登录页面""" if request.method == 'POST': username = request.form['username'].strip() password = request.form['password'] users = load_users() if username not in users: flash('用户名不存在', 'error') return render_template('login.html') if users[username]['password'] != hash_password(password): flash('密码不正确', 'error') return render_template('login.html') session['username'] = username flash('登录成功!', 'success') return redirect(url_for('diary')) return render_template('login.html') @app.route('/register', methods=['GET', 'POST']) def register(): """注册页面""" if request.method == 'POST': username = request.form['username'].strip() password = request.form['password'] confirm_password = request.form['confirm_password'] if not username or not password: flash('请输入用户名和密码', 'error') return render_template('register.html') if password != confirm_password: flash('两次输入的密码不一致', 'error') return render_template('register.html') users = load_users() if username in users: flash('用户名已存在', 'error') return render_template('register.html') # 创建新用户 users[username] = { 'password': hash_password(password), 'created_at': datetime.now().strftime('%Y-%m-%d %H:%M:%S') } save_users(users) # 创建空的日记文件 save_user_diaries(username, {}) flash('注册成功!请登录', 'success') return redirect(url_for('login')) return render_template('register.html') @app.route('/diary') @login_required def diary(): """日记主页面""" selected_date = request.args.get('date', date.today().strftime('%Y-%m-%d')) try: datetime.strptime(selected_date, '%Y-%m-%d') except ValueError: selected_date = date.today().strftime('%Y-%m-%d') diaries = load_user_diaries(session['username']) content = diaries.get(selected_date, '') return render_template('diary.html', current_date=selected_date, content=content, username=session['username']) @app.route('/save_diary', methods=['POST']) @login_required def save_diary(): """保存日记""" diary_date = request.form['date'] content = request.form['content'] try: datetime.strptime(diary_date, '%Y-%m-%d') except ValueError: return jsonify({'success': False, 'message': '日期格式错误'}) diaries = load_user_diaries(session['username']) diaries[diary_date] = content save_user_diaries(session['username'], diaries) return jsonify({'success': True, 'message': '日记保存成功'}) @app.route('/calendar') @login_required def calendar(): """日历页面""" diaries = load_user_diaries(session['username']) # 获取有日记的日期列表 diary_dates = list(diaries.keys()) return render_template('calendar.html', diary_dates=diary_dates, username=session['username']) @app.route('/get_diary_dates') @login_required def get_diary_dates(): """获取有日记的日期列表(API)""" diaries = load_user_diaries(session['username']) return jsonify(list(diaries.keys())) @app.route('/logout') def logout(): """退出登录""" session.pop('username', None) flash('已退出登录', 'success') return redirect(url_for('login')) if __name__ == '__main__': init_data_dir() app.run(debug=True, port=5000)

login.html:

{% extends "base.html" %} {% block title %}登录 - 个人日记本{% endblock %} {% block content %} <div class="auth-container"> <h2>用户登录</h2> <form method="POST" class="auth-form"> <div class="form-group"> <label for="username">用户名:</label> <input type="text" id="username" name="username" required> </div> <div class="form-group"> <label for="password">密码:</label> <input type="password" id="password" name="password" required> </div> <button type="submit" class="btn">登录</button> </form> <p>还没有账户? <a href="{{ url_for('register') }}">立即注册</a></p> </div> {% endblock %}

base.html

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{% block title %}个人日记本{% endblock %}</title> <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}"> </head> <body> <div class="container"> <header> <h1>个人日记本</h1> {% if session.username %} <div class="user-info"> 欢迎, {{ session.username }} | <a href="{{ url_for('calendar') }}">日历</a> | <a href="{{ url_for('diary') }}">写日记</a> | <a href="{{ url_for('logout') }}">退出</a> </div> {% endif %} </header> {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} <div class="flash-messages"> {% for category, message in messages %} <div class="flash {{ category }}">{{ message }}</div> {% endfor %} </div> {% endif %} {% endwith %} <main> {% block content %}{% endblock %} </main> </div> </body> </html>

register.html:

{% extends "base.html" %} {% block title %}注册 - 个人日记本{% endblock %} {% block content %} <div class="auth-container"> <h2>用户注册</h2> <form method="POST" class="auth-form"> <div class="form-group"> <label for="username">用户名:</label> <input type="text" id="username" name="username" required> </div> <div class="form-group"> <label for="password">密码:</label> <input type="password" id="password" name="password" required> </div> <div class="form-group"> <label for="confirm_password">确认密码:</label> <input type="password" id="confirm_password" name="confirm_password" required> </div> <button type="submit" class="btn">注册</button> </form> <p>已有账户? <a href="{{ url_for('login') }}">立即登录</a></p> </div> {% endblock %}

diary.html:

{% extends "base.html" %} {% block title %}写日记 - 个人日记本{% endblock %} {% block content %} <div class="diary-container"> <h2>我的日记</h2> <div class="date-selector"> <label for="date">选择日期:</label> <input type="date" id="date" value="{{ current_date }}"> <button onclick="loadDiary()" class="btn">加载</button> <button onclick="gotoToday()" class="btn">今天</button> </div> <div class="editor-container"> <textarea id="content" placeholder="写下今天的心情...">{{ content }}</textarea> </div> <div class="actions"> <button onclick="saveDiary()" class="btn btn-primary">保存日记</button> <span id="message" class="message"></span> </div> </div> <script> function loadDiary() { const date = document.getElementById('date').value; window.location.href = "{{ url_for('diary') }}?date=" + date; } function gotoToday() { const today = new Date().toISOString().split('T')[0]; document.getElementById('date').value = today; loadDiary(); } async function saveDiary() { const date = document.getElementById('date').value; const content = document.getElementById('content').value; const response = await fetch("{{ url_for('save_diary') }}", { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: `date=${encodeURIComponent(date)}&content=${encodeURIComponent(content)}` }); const result = await response.json(); document.getElementById('message').textContent = result.message; document.getElementById('message').className = result.success ? 'message success' : 'message error'; setTimeout(() => { document.getElementById('message').textContent = ''; }, 3000); } </script> {% endblock %}

calendar.html:

{% extends "base.html" %} {% block title %}日历 - 个人日记本{% endblock %} {% block content %} <div class="calendar-container"> <h2>日记日历</h2> <p>点击有日记的日期查看内容</p> <div class="diary-dates"> <h3>有日记的日期:</h3> <div class="dates-list"> {% for diary_date in diary_dates %} <a href="{{ url_for('diary') }}?date={{ diary_date }}" class="date-link"> {{ diary_date }} </a> {% else %} <p>还没有写过日记呢</p> {% endfor %} </div> </div> </div> {% endblock %}

代码请自取,分享地址:https://gitcode.com/javy21/p_diaries.git

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/15 13:27:46

FPGA新手零基础实战:Vivado环境搭建与LED流水灯设计

1. Vivado开发环境安装与配置 第一次接触FPGA开发时&#xff0c;安装Vivado可能会让人有点懵。我刚开始用Vivado 2023.1版本时&#xff0c;光是安装就踩了不少坑。这里分享几个关键点&#xff1a; 首先去Xilinx官网下载WebPACK免费版本&#xff08;现在属于AMD旗下&#xff09…

作者头像 李华
网站建设 2026/7/15 13:27:42

2024安卓逆向实战指南——Pixel真机刷机与Root环境一站式搭建

1. 为什么选择Pixel手机做逆向开发&#xff1f; 如果你刚接触安卓逆向&#xff0c;可能会纠结该选哪款设备。我这些年用过各种品牌的测试机&#xff0c;最后发现 Google Pixel系列 是最省心的选择。原因很简单&#xff1a;官方支持完善、社区资源丰富、解锁限制少。举个例子&…

作者头像 李华
网站建设 2026/7/15 13:27:25

怎样高效解决Windows窗口尺寸问题:WindowResizer完整实用指南

怎样高效解决Windows窗口尺寸问题&#xff1a;WindowResizer完整实用指南 【免费下载链接】WindowResizer 一个可以强制调整应用程序窗口大小的工具 项目地址: https://gitcode.com/gh_mirrors/wi/WindowResizer 还在为Windows应用程序窗口尺寸限制而烦恼吗&#xff1f;…

作者头像 李华
网站建设 2026/7/15 13:26:44

如何在5分钟内使用html-to-docx将HTML完美转换为Word文档:终极指南

如何在5分钟内使用html-to-docx将HTML完美转换为Word文档&#xff1a;终极指南 【免费下载链接】html-to-docx HTML to DOCX converter 项目地址: https://gitcode.com/gh_mirrors/ht/html-to-docx 还在为网页内容转换到Word文档而烦恼吗&#xff1f;复制粘贴导致表格变…

作者头像 李华
网站建设 2026/7/15 13:26:15

革命性智能自动化:7倍效率重塑炉石传说游戏体验

革命性智能自动化&#xff1a;7倍效率重塑炉石传说游戏体验 【免费下载链接】Hearthstone-Script Hearthstone script&#xff08;炉石传说脚本&#xff09; 项目地址: https://gitcode.com/gh_mirrors/he/Hearthstone-Script 还在为炉石传说中重复机械的任务操作而烦恼…

作者头像 李华