一、项目简介
社区问答平台是典型的内容型全栈项目,用户可以发布技术问题,其他用户可以回答、点赞并采纳最佳答案。它的业务形态类似 Stack Overflow、知乎问答与技术社区中的问答模块,非常适合练习"后端接口 + 数据库建模 + 前端交互"的完整开发流程。
本文以 "Python全栈项目--基于Django的社区问答平台" 为主题,围绕 Django 社区问答平台常见业务进行设计。为了让示例项目更轻量、更容易直接运行,源码实现采用 FastAPI + SQLite + 原生 HTML/CSS/JavaScript,但系统分层、模型关系、接口设计与 Django 项目中的 MVT/ORM 思路保持一致:后端负责模型、接口和业务逻辑,前端负责页面渲染与交互。
项目最终实现以下能力:
- 用户创建与复用;
- 问题发布;
- 问题列表展示;
- 关键词与标签搜索;
- 问题回答;
- 回答点赞;
- 回答采纳;
- SQLite 数据持久化;
- 前后端分离调用。
二、技术栈
| 层级 | 技术 | 说明 |
|---|---|---|
| 后端框架 | FastAPI | 提供 RESTful API,开发体验接近现代 Python Web 框架 |
| 数据库 | SQLite | 单文件数据库,适合课程设计、毕业设计 Demo 和本地部署 |
| ORM | SQLAlchemy | 定义用户、问题、回答模型及关系 |
| 数据校验 | Pydantic | 定义请求体和响应结构 |
| 前端 | HTML/CSS/JavaScript | 不依赖构建工具,浏览器直接运行 |
| 接口调用 | Fetch API | 前端通过 HTTP 请求访问后端 |
| 部署 | Uvicorn + 静态页面 | 后端启动 API 服务,前端直接打开或用 http.server 托管 |
三、系统架构
项目采用前后端分离架构:
text
浏览器前端
├── index.html 页面结构
├── style.css 页面样式
└── app.js 接口请求与 DOM 渲染
│ fetch
▼
FastAPI 后端
├── main.py 路由入口、跨域、启动初始化
├── database.py SQLite 连接
├── models.py 用户/问题/回答数据表
├── schemas.py 请求响应模型
└── crud.py 增删查改业务逻辑
│ SQLAlchemy
▼
SQLite 数据库 qa_community.db
后端将所有核心能力封装成 /api 接口,前端不直接操作数据库,而是通过 fetch 调用接口完成页面数据刷新。这种模式便于后续替换为 Vue、React,或将后端迁移到真正的 Django REST Framework。
四、功能模块
1. 用户模块
用户模块用于创建或复用用户。为了简化登录流程,示例项目没有加入密码和 JWT,而是通过用户名创建用户。如果用户名已存在,就复用原用户,并可更新简介。
2. 问题模块
问题模块是系统核心,支持:
- 发布问题;
- 查看问题列表;
- 根据关键词搜索标题和正文;
- 根据标签筛选;
- 记录浏览量;
- 关联作者与回答列表。
3. 回答模块
回答模块支持用户对问题进行回复,每条回答记录回答者、内容、点赞数、是否被采纳和创建时间。
4. 互动模块
互动模块包含回答点赞与采纳。采纳时,同一个问题下只保留一个已采纳答案,其余答案自动取消采纳状态。
五、数据库/数据模型设计
本项目包含三张核心表:users、questions、answers。
1. 用户表 users
| 字段 | 类型 | 说明 |
|---|---|---|
| id | Integer | 主键 |
| username | String | 用户名,唯一 |
| bio | String | 用户简介 |
| created_at | DateTime | 创建时间 |
2. 问题表 questions
| 字段 | 类型 | 说明 |
|---|---|---|
| id | Integer | 主键 |
| title | String | 问题标题 |
| content | Text | 问题正文 |
| tags | String | 标签,逗号分隔 |
| views | Integer | 浏览量 |
| created_at | DateTime | 创建时间 |
| author_id | Integer | 作者用户 ID |
3. 回答表 answers
| 字段 | 类型 | 说明 |
|---|---|---|
| id | Integer | 主键 |
| content | Text | 回答内容 |
| likes | Integer | 点赞数 |
| accepted | Integer | 是否采纳,1 表示采纳 |
| created_at | DateTime | 创建时间 |
| question_id | Integer | 所属问题 ID |
| author_id | Integer | 回答者用户 ID |
模型关系为:
text
User 1 --- N Question
User 1 --- N Answer
Question 1 --- N Answer
六、后端接口设计
| 方法 | 路径 | 功能 |
|---|---|---|
| GET | /api/health |
健康检查 |
| POST | /api/users |
创建或获取用户 |
| GET | /api/questions |
查询问题列表,支持 keyword/tag |
| POST | /api/questions |
发布问题 |
| GET | /api/questions/{question_id} |
查看问题详情 |
| POST | /api/questions/{question_id}/answers |
提交回答 |
| POST | /api/answers/{answer_id}/like |
给回答点赞 |
| POST | /api/questions/{question_id}/answers/{answer_id}/accept |
采纳回答 |
示例:发布问题请求体如下:
json
{
"title": "Django 项目中如何设计问题与回答模型?",
"content": "社区问答平台需要支持问题、回答、标签、浏览量与采纳状态。",
"tags": "Django,SQLite,全栈",
"author_id": 1
}
七、前端页面设计
前端页面分为两个区域:
- 左侧发布区:填写用户名、简介、问题标题、标签和问题内容;
- 右侧问题广场:展示问题列表、搜索框、回答列表、点赞和采纳按钮。
页面交互逻辑:
- 页面加载时请求
/api/questions; - 点击"提交问题"时先创建/获取用户,再提交问题;
- 点击"搜索"时拼接
keyword和tag查询参数; - 提交回答时先创建/获取回答者,再调用回答接口;
- 点赞和采纳后重新加载问题列表。
八、核心代码讲解
1. 数据库连接 database.py
python
from sqlalchemy import create_engine
from sqlalchemy.orm import declarative_base, sessionmaker
DATABASE_URL = "sqlite:///./qa_community.db"
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
engine 负责连接 SQLite,SessionLocal 用于为每个请求创建数据库会话,Base 是所有模型类的基类。
2. 问题与回答模型 models.py
python
class Question(Base):
__tablename__ = "questions"
id = Column(Integer, primary_key=True, index=True)
title = Column(String(120), index=True, nullable=False)
content = Column(Text, nullable=False)
tags = Column(String(120), default="Python")
views = Column(Integer, default=0)
author_id = Column(Integer, ForeignKey("users.id"), nullable=False)
author = relationship("User", back_populates="questions")
answers = relationship("Answer", back_populates="question", cascade="all, delete-orphan")
这里用 ForeignKey 建立问题与用户的关系,一个用户可以发布多个问题;问题与回答是一对多关系。
3. 搜索业务 crud.py
python
def list_questions(db, keyword=None, tag=None):
query = db.query(models.Question)
if keyword:
pattern = f"%{keyword}%"
query = query.filter(or_(models.Question.title.like(pattern), models.Question.content.like(pattern)))
if tag:
query = query.filter(models.Question.tags.like(f"%{tag}%"))
return query.order_by(models.Question.created_at.desc()).all()
该函数同时支持关键词搜索和标签筛选,是问答平台中最常见的查询能力。
4. 路由入口 main.py
python
@app.get("/api/questions", response_model=list[schemas.QuestionOut])
def list_questions(keyword: str | None = None, tag: str | None = None, db: Session = Depends(get_db)):
return crud.list_questions(db, keyword=keyword, tag=tag)
FastAPI 自动解析查询参数,并将数据库会话注入到路由函数中。response_model 负责规范输出结构,让前端拿到稳定的数据格式。
5. 前端请求 app.js
javascript
async function request(path, options = {}) {
const res = await fetch(`${API_BASE}${path}`, {
headers: { 'Content-Type': 'application/json' },
...options,
});
if (!res.ok) throw new Error('请求失败');
return res.json();
}
前端统一封装请求函数,后续发布问题、查询问题、点赞和采纳都复用该函数,避免重复代码。
九、部署与运行步骤
1. 安装依赖
进入后端目录:
bash
cd project/backend
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
2. 启动后端
bash
uvicorn app.main:app --reload
启动成功后访问:
text
http://127.0.0.1:8000/docs
可以在 Swagger 页面测试所有接口。
3. 打开前端
方式一:直接打开 project/frontend/index.html。
方式二:在 project 目录启动静态服务:
bash
python3 -m http.server 5500
然后访问:
text
http://127.0.0.1:5500/frontend/index.html
4. 初始化数据
后端首次启动时会自动创建 SQLite 数据库文件 qa_community.db,并写入两个示例用户、两个示例问题和两条示例回答,无需手动执行 SQL。
十、项目扩展方向
如果需要把该项目进一步升级为真正的生产级 Django 社区问答平台,可以继续增加:
- 用户注册、登录、JWT 或 Session 鉴权;
- Markdown 编辑器与代码高亮;
- 问题收藏、关注标签、邀请回答;
- 评论系统和通知系统;
- 后台管理页面;
- Redis 缓存热门问题;
- Elasticsearch 全文搜索;
- Docker Compose 一键部署。
十一、项目总结
本文完成了一个社区问答平台全栈项目,从系统架构、数据模型、接口设计到前端页面交互进行了完整拆解。该项目虽然使用轻量化技术栈实现,但业务结构与 Django 问答平台高度一致,包含用户、问题、回答、搜索、点赞与采纳等核心能力。
通过这个项目,可以系统练习:
- Python Web 后端接口开发;
- ORM 数据建模;
- RESTful API 设计;
- 前端 Fetch 调用接口;
- 前后端分离项目组织;
- SQLite 本地持久化;
- 全栈项目部署与说明文档编写。
对于课程设计、毕业设计原型、CSDN 技术博文或全栈开发入门练习来说,这是一个结构清晰、功能完整、便于扩展的项目模板。