CREATE TABLE messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
content TEXT NOT NULL,
ip TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_messages_created_at ON messages(created_at DESC);
from flask import Flask, request, render_template_string, g
import sqlite3, os
app = Flask(__name__)
DB = 'messages.db'
def get_db():
if 'db' not in g:
g.db = sqlite3.connect(DB)
g.db.row_factory = sqlite3.Row
return g.db
@app.teardown_appcontext
def close_db(e=None):
db = g.pop('db', None)
if db: db.close()
def init_db():
with app.app_context():
db = get_db()
db.executescript(open('schema.sql').read())
db.commit()
HTML = """
<!doctype html>
<html><head><title>留言板</title>
<style>body{max-width:600px;margin:2rem auto;font-family:sans-serif}
.msg{border-bottom:1px solid #eee;padding:1rem 0}
.msg meta{color:#888;font-size:.9em}
form{display:flex;gap:.5rem;margin-bottom:2rem}
textarea{flex:1;min-height:80px}
button{padding:.5rem 1rem}
</style></head><body>
<h1>留言板</h1>
<form method=post>
<textarea name=content placeholder="說點什麼..." required></textarea>
<button type=submit>發布</button>
</form>
{% for m in messages %}
<div class=msg>
<p>{{ m.content }}</p>
<meta>IP: {{ m.ip }} | {{ m.created_at }}</meta>
</div>
{% endfor %}
</body></html>
"""
@app.route('/', methods=['GET', 'POST'])
def index():
db = get_db()
if request.method == 'POST':
content = request.form['content'].strip()
if content:
ip = request.headers.get('X-Forwarded-For', request.remote_addr)
db.execute('INSERT INTO messages (content, ip) VALUES (?, ?)', (content, ip))
db.commit()
# 倒序顯示
cur = db.execute('SELECT content, ip, created_at FROM messages ORDER BY created_at DESC')
messages = cur.fetchall()
return render_template_string(HTML, messages=messages)
if __name__ == '__main__':
if not os.path.exists(DB): init_db()
app.run(debug=True)
ORDER BY created_at DESC + 索引確保大量資料查詢快速。X-Forwarded-For 標頭。{{ m.content }},安全顯示使用者輸入。SQLite 輕量零配置,極適合「單檔案、單頁面、低併發」留言板。核心邏輯:**建表含時間/IP 索引 → POST 插入 → GET 倒序查詢 → 模板渲染**。Python Flask 版本約 50 行即可完成功能,易於理解與擴充。