项目概述
本项目将带领大家使用Flask框架开发一个功能完整的个人博客系统。通过这个项目,你将学习到Web开发的核心概念和实践技能。
项目特点:
- 完整的用户认证系统
- 文章的CRUD操作
- 评论和回复功能
- Markdown编辑器支持
- 响应式页面设计
技术栈说明
后端技术
- Flask - Web框架
- SQLite - 数据库
- SQLAlchemy - ORM框架
- Flask-Login - 用户认证
前端技术
- Bootstrap - UI框架
- SimpleMDE - Markdown编辑器
- jQuery - JavaScript库
项目结构
blog/
├── app/
│ ├── __init__.py
│ ├── models.py
│ ├── routes.py
│ └── templates/
├── config.py
├── requirements.txt
└── run.py
数据库设计
我们使用SQLAlchemy作为ORM框架,设计以下数据模型:
# models.py
from app import db
from datetime import datetime
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password_hash = db.Column(db.String(128))
posts = db.relationship('Post', backref='author', lazy=True)
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(200), nullable=False)
content = db.Column(db.Text, nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
comments = db.relationship('Comment', backref='post', lazy=True)
class Comment(db.Model):
id = db.Column(db.Integer, primary_key=True)
content = db.Column(db.Text, nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False)
用户认证
使用Flask-Login实现用户认证系统:
# routes.py
from flask import render_template, flash, redirect, url_for
from flask_login import login_user, logout_user, login_required
from app import app, db
from app.models import User
from app.forms import LoginForm, RegisterForm
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegisterForm()
if form.validate_on_submit():
user = User(username=form.username.data, email=form.email.data)
user.set_password(form.password.data)
db.session.add(user)
db.session.commit()
flash('注册成功!')
return redirect(url_for('login'))
return render_template('auth/register.html', form=form)
@app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()
if user and user.check_password(form.password.data):
login_user(user)
return redirect(url_for('index'))
flash('用户名或密码错误')
return render_template('auth/login.html', form=form)
文章管理
实现文章的CRUD操作:
# routes.py
@app.route('/post/new', methods=['GET', 'POST'])
@login_required
def new_post():
form = PostForm()
if form.validate_on_submit():
post = Post(title=form.title.data,
content=form.content.data,
author=current_user)
db.session.add(post)
db.session.commit()
flash('文章发布成功!')
return redirect(url_for('post', post_id=post.id))
return render_template('post/editor.html', form=form)
@app.route('/post/')
def post(post_id):
post = Post.query.get_or_404(post_id)
return render_template('post/detail.html', post=post)
@app.route('/post//edit', methods=['GET', 'POST'])
@login_required
def edit_post(post_id):
post = Post.query.get_or_404(post_id)
if post.author != current_user:
abort(403)
form = PostForm()
if form.validate_on_submit():
post.title = form.title.data
post.content = form.content.data
db.session.commit()
flash('文章更新成功!')
return redirect(url_for('post', post_id=post.id))
form.title.data = post.title
form.content.data = post.content
return render_template('post/editor.html', form=form, edit=True)
@app.route('/post//delete', methods=['POST'])
@login_required
def delete_post(post_id):
post = Post.query.get_or_404(post_id)
if post.author != current_user:
abort(403)
db.session.delete(post)
db.session.commit()
flash('文章已删除')
return redirect(url_for('index'))
安全提示:
- 验证用户权限
- 防止CSRF攻击
- 过滤用户输入
- 限制请求频率
评论系统
实现评论和回复功能:
# routes.py
@app.route('/post//comment', methods=['POST'])
@login_required
def add_comment(post_id):
post = Post.query.get_or_404(post_id)
form = CommentForm()
if form.validate_on_submit():
comment = Comment(content=form.content.data,
post=post,
author=current_user)
db.session.add(comment)
db.session.commit()
flash('评论发布成功!')
return redirect(url_for('post', post_id=post_id))
@app.route('/comment//reply', methods=['POST'])
@login_required
def reply_comment(comment_id):
parent = Comment.query.get_or_404(comment_id)
form = CommentForm()
if form.validate_on_submit():
reply = Comment(content=form.content.data,
post=parent.post,
author=current_user,
parent_id=parent.id)
db.session.add(reply)
db.session.commit()
flash('回复发布成功!')
return redirect(url_for('post', post_id=parent.post_id))
# templates/post/detail.html
{% for comment in post.comments %}
{{ comment.content }}
{% if current_user.is_authenticated %}
{% endif %}
{% endfor %}
项目部署
使用Gunicorn和Nginx部署项目:
# gunicorn配置
gunicorn -w 4 -b 127.0.0.1:8000 run:app
# nginx配置
server {
listen 80;
server_name your_domain.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}