帖子模块设计文档
1. 数据库设计
1.1 Post表
class Post(models.Model):
id = models.AutoField(primary_key=True)
course = models.ForeignKey(Course, on_delete=models.CASCADE)
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
content = models.TextField() # HTML内容
mentioned_users = models.JSONField(default=list, blank=True) # ['user_id1', 'user_id2']
topic = models.CharField(max_length=50, blank=True) # 单个话题标签
likes_count = models.PositiveIntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
索引设计
class Meta:
ordering = ['-created_at']
indexes = [
models.Index(fields=['topic']), # 为话题搜索添加索引
models.Index(fields=['course', 'created_at']), # 为课程内帖子列表添加索引
]
1.2 关联表设计
- Note表:用于存储用户笔记
- Notification表:用于存储通知信息
- Comment表:用于存储帖子评论
2. 服务器架构
2.1 服务器组成
- Django后端服务器:处理业务逻辑
- 远程文件服务器:存储帖子图片
- Redis远程服务器:处理点赞缓存和临时数据
2.2 数据存储策略
- 文本内容:存储在MySQL数据库中
- 图片内容:存储在文件服务器,数据库仅存储URL
- 点赞数据:
- 总数存储在数据库
- 用户点赞关系存储在Redis
- 定期同步Redis数据到数据库
3. 帖子创建流程
3.1 前端实现(Vue + TinyMCE)
用户交互:
- 使用TinyMCE编辑器编写富文本内容
- 上传图片获取临时URL
- 添加@用户标记
- 设置话题标签
数据收集:
- HTML内容
- 图片映射信息(临时URL到文件的映射)
- @用户列表
- 话题标签
3.2 后端处理(Django)
- 接收前端数据
- 图片处理:
- 解析HTML提取临时URL
- 上传图片至文件服务器
- 获取永久URL
- 替换HTML中的临时URL
- 保存帖子数据到数据库
4. 点赞机制
4.1 Redis键值设计
article:likes:{id} - 存储帖子点赞总数
article:likes:update:{id} - 存储待更新到数据库的点赞数
article:liked_users:{id} - 存储已点赞用户集合
4.2 点赞流程
获取帖子列表:
- 请求携带user_id
- 通过Redis Pipeline获取点赞数和用户点赞状态
- Redis无数据时从数据库获取并缓存
点赞操作:
- 检查用户是否已点赞
- Pipeline执行:
- 添加用户到点赞集合
- 增加点赞总数
- 增加待更新数
- 返回最新点赞数
取消点赞:
- 检查用户是否已点赞
- Pipeline执行:
- 从点赞集合移除用户
- 减少点赞总数
- 减少待更新数
- 返回最新点赞数
4.3 数据同步
- 后台线程每60秒执行一次同步
- 获取所有待更新的点赞数
- 批量更新数据库
- 清零Redis更新计数器
5. 优化策略
5.1 数据库优化
- 为高频查询添加索引
- 使用JSON字段存储非结构化数据
5.2 缓存优化
- 使用Redis缓存点赞数据
- Pipeline操作保证原子性
- 异步同步减少数据库压力
5.3 性能优化
- 图片与文本分离存储
- 利用Redis减少数据库访问
- 批量操作代替频繁单次操作
- 合理设置索引提升查询效率
6. 扩展性考虑
- 模块化设计便于功能扩展
- 服务分离支持横向扩展
- 预留字段支持未来功能
- 统一的错误处理机制
敲代码过程中的经验
1,django后端中也要有回滚,若帖子创建过程中失败,则应删除数据库中的内容;
2,由于json在传输过程中会给双引号添加转译字符,因此存放帖子内容时应统一使用单引号;
def process_post_images(content, image_map, post_id):
"""处理帖子中的图片,返回替换后的内容"""
# 1. 首先统一将内容中的双引号替换为单引号
content = content.replace('"', "'")
# 2. 获取所有临时图片URL(同时支持单引号和双引号的匹配)
temp_urls = re.findall(r"src=['\"]temp://([^'\"]+)['\"]", content)
# 验证所有临时URL都有对应的文件
missing_files = set(temp_urls) - set(
key.replace('image_map[temp://', '').replace(']', '')
for key in image_map.keys()
)
if missing_files:
raise ValidationError(f"缺少图片文件: {', '.join(missing_files)}")
# 3. 上传图片并替换URL(统一使用单引号)
for temp_url in temp_urls:
file_key = f"image_map[temp://{temp_url}]"
if file_key in image_map:
file = image_map[file_key]
permanent_url = PostService.upload_post_image(file, post_id)
content = content.replace(
f"temp://{temp_url}",
permanent_url
)
return content
评论区