【导航台账】老蒋的技术博客全系列文章汇总(持续更新)
下面是一个简单的个人日记本程序,使用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