
【导航台账】老蒋的技术博客全系列文章汇总持续更新下面是一个简单的个人日记本程序使用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, encodingutf-8) as f: json.dump({}, f, ensure_asciiFalse, indent2) def hash_password(password): 密码哈希函数 return hashlib.sha256(password.encode()).hexdigest() def load_users(): 加载用户数据 try: with open(USERS_FILE, r, encodingutf-8) as f: return json.load(f) except (FileNotFoundError, json.JSONDecodeError): return {} def save_users(users): 保存用户数据 with open(USERS_FILE, w, encodingutf-8) as f: json.dump(users, f, ensure_asciiFalse, indent2) 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, encodingutf-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, encodingutf-8) as f: json.dump(diaries, f, ensure_asciiFalse, indent2) 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_dateselected_date, contentcontent, usernamesession[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_datesdiary_dates, usernamesession[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(debugTrue, port5000)login.html:{% extends base.html %} {% block title %}登录 - 个人日记本{% endblock %} {% block content %} div classauth-container h2用户登录/h2 form methodPOST classauth-form div classform-group label forusername用户名:/label input typetext idusername nameusername required /div div classform-group label forpassword密码:/label input typepassword idpassword namepassword required /div button typesubmit classbtn登录/button /form p还没有账户 a href{{ url_for(register) }}立即注册/a/p /div {% endblock %}base.html!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title{% block title %}个人日记本{% endblock %}/title link relstylesheet href{{ url_for(static, filenamestyle.css) }} /head body div classcontainer header h1个人日记本/h1 {% if session.username %} div classuser-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_categoriestrue) %} {% if messages %} div classflash-messages {% for category, message in messages %} div classflash {{ category }}{{ message }}/div {% endfor %} /div {% endif %} {% endwith %} main {% block content %}{% endblock %} /main /div /body /htmlregister.html:{% extends base.html %} {% block title %}注册 - 个人日记本{% endblock %} {% block content %} div classauth-container h2用户注册/h2 form methodPOST classauth-form div classform-group label forusername用户名:/label input typetext idusername nameusername required /div div classform-group label forpassword密码:/label input typepassword idpassword namepassword required /div div classform-group label forconfirm_password确认密码:/label input typepassword idconfirm_password nameconfirm_password required /div button typesubmit classbtn注册/button /form p已有账户 a href{{ url_for(login) }}立即登录/a/p /div {% endblock %}diary.html:{% extends base.html %} {% block title %}写日记 - 个人日记本{% endblock %} {% block content %} div classdiary-container h2我的日记/h2 div classdate-selector label fordate选择日期:/label input typedate iddate value{{ current_date }} button onclickloadDiary() classbtn加载/button button onclickgotoToday() classbtn今天/button /div div classeditor-container textarea idcontent placeholder写下今天的心情...{{ content }}/textarea /div div classactions button onclicksaveDiary() classbtn btn-primary保存日记/button span idmessage classmessage/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 classcalendar-container h2日记日历/h2 p点击有日记的日期查看内容/p div classdiary-dates h3有日记的日期:/h3 div classdates-list {% for diary_date in diary_dates %} a href{{ url_for(diary) }}?date{{ diary_date }} classdate-link {{ diary_date }} /a {% else %} p还没有写过日记呢/p {% endfor %} /div /div /div {% endblock %}源代码请自取分享地址:https://gitcode.com/javy21/p_diaries.git