Files
diary-family/README.md

2115 lines
54 KiB
Markdown
Raw Normal View History

2026-01-04 19:21:52 +08:00
# 家庭日报系统
专注于家庭生活的轻量级日报系统使用Django框架开发。
2026-01-04 19:21:52 +08:00
## 功能特性
2026-01-04 19:21:52 +08:00
### 核心功能模块
#### 1. 阅读记录管理
- 支持添加、编辑、删除阅读记录
- 阅读类型分类管理(如:书籍、文章、论文等)
- 记录阅读标题、来源、进度
- 支持添加阅读笔记
- 支持文件上传(阅读相关资料)
- 支持查看昨日和今日的阅读记录
#### 2. 感悟记录管理
- 支持添加、编辑、删除感悟记录
- 支持选择发言人(家庭成员)
- 感悟内容记录
- 支持文件上传(感悟相关资料)
- 支持查看昨日和今日的感悟记录
#### 3. 汇总记录管理
- 支持添加、编辑、删除汇总记录
- 汇总分类管理(如:新闻、知识、生活等)
- 支持选择发言人和来源
- 汇总内容记录
- 支持文件上传
#### 4. 家庭事项管理
- 支持添加、编辑、删除家庭事项
- 自定义事项类型
- 设置优先级(高、中、低)
- 设置状态(待处理、已完成等)
- 设置截止日期
- 支持按优先级和截止日期排序
#### 5. 今日计划管理
- 支持添加、编辑、删除今日计划
- 设置计划类型
- 设置优先级
- 设置状态(待处理、已完成)
- 支持状态快速切换
- 支持选择发言人
- 按优先级排序显示
#### 6. 报告生成与查看
- 自动生成每日家庭日报
- 报告内容包括:
- 昨日阅读记录汇总
- 昨日感悟记录汇总
- 昨日汇总记录
- 今日计划列表
- 家庭事项统计
- 支持查看历史报告
- 支持选择不同日期查看报告
#### 7. PDF报告生成
- 使用WeasyPrint生成PDF格式报告
- 支持报告预览HTML格式与PDF样式一致
- 支持下载PDF文件
- PDF文件自动保存到服务器
- 支持查看历史PDF文件列表
#### 8. 邮件发送功能
- 支持SMTP邮件发送
- 邮件包含PDF报告附件
- 支持定时发送通过Celery Beat
- 支持手动发送
- 可配置发送时间
- 支持多个收件人
#### 9. 系统配置
- SMTP服务器配置
- 发送时间设置
- 发件人邮箱配置
- 收件人邮箱配置
- 通过Web界面进行配置
#### 10. 后台管理界面
- 完整的Django Admin后台
- 访问路径:/houtai
- 管理所有数据模型
- 管理用户和权限
### 数据模型
| 模型 | 说明 | 主要字段 |
|-----|------|---------|
| ReadingType | 阅读记录类型 | name |
| FamilyTaskType | 家庭事项类型 | name |
| Priority | 优先级 | name |
| Status | 状态 | name |
| PlanType | 今日计划类型 | name |
| FamilyMember | 家庭成员 | name |
| ReadingRecord | 阅读记录 | date, type, title, source, progress, note, file |
| InsightRecord | 感悟记录 | date, content, speaker, file |
| Summary | 汇总记录 | date, category, speaker, content, source, file |
| FamilyTask | 家庭事项 | type, content, priority, status, deadline |
| TodayPlan | 今日计划 | date, content, speaker, priority, type, status |
| SystemConfig | 系统配置 | smtp_server, send_time, recipient_email等 |
### 异步任务
系统使用Celery处理异步任务
- `generate_daily_pdf_report`每日PDF报告生成
- `send_daily_report`:每日邮件发送
- 依赖Redis作为消息代理
- 支持定时任务调度
2026-01-04 19:21:52 +08:00
## 技术栈
2026-01-04 19:21:52 +08:00
- Python 3.10+
- Django 4.2+
- Bootstrap 5
- SQLite开发环境
- PostgreSQL/MySQL生产环境
- Gunicorn + Nginx生产部署
2026-01-04 19:21:52 +08:00
## 快速开始
2026-01-04 19:21:52 +08:00
### 安装依赖
```bash
pip install -r requirements.txt
```
### 运行开发服务器
2026-01-04 19:21:52 +08:00
```bash
python manage.py runserver
```
### 访问系统
打开浏览器访问http://127.0.0.1:8000
2026-01-04 19:21:52 +08:00
## 数据库迁移指南
2026-01-04 19:21:52 +08:00
### 基本迁移流程
2026-01-04 19:21:52 +08:00
1. 生成迁移文件:
```bash
python manage.py makemigrations
```
2026-01-05 21:33:18 +08:00
2. 查看迁移文件内容(重要!):
```bash
cat core/migrations/000x_xxx.py
```
2026-01-05 21:33:18 +08:00
3. 应用迁移:
```bash
python manage.py migrate
```
2026-01-05 21:33:18 +08:00
### 当数据库有数据时增加字段
2026-01-05 21:33:18 +08:00
#### 问题说明
2026-01-05 21:33:18 +08:00
当数据库中已有数据时通过Django的migrate命令增加新字段**不会删除原有数据**,但需要注意以下几点:
2026-01-05 21:33:18 +08:00
1. 如果新字段设置为**非空**`null=False, blank=False`),则必须提供默认值,否则迁移会失败
2. 如果新字段设置为**可空**`null=True, blank=True`则迁移会自动执行原有记录的新字段值为NULL
2026-01-05 21:33:18 +08:00
#### 正确部署流程
2026-01-05 21:33:18 +08:00
1. **在开发环境测试**
- 首先在开发环境生成迁移文件
- 检查迁移文件内容,确保:
- 新字段设置为可空(`null=True, blank=True`),或者
- 新字段提供了合理的默认值
- 在开发环境执行迁移,测试功能是否正常
2026-01-05 21:33:18 +08:00
2. **备份生产数据库**(重要!):
```bash
# PostgreSQL示例
pg_dump -U username -d dbname > backup_$(date +%Y%m%d_%H%M%S).sql
# MySQL示例
mysqldump -u username -p dbname > backup_$(date +%Y%m%d_%H%M%S).sql
```
2026-01-05 21:33:18 +08:00
3. **在生产环境执行迁移**
```bash
# 进入项目目录
cd /path/to/diary-family
# 激活虚拟环境
source venv/bin/activate
# 生成迁移文件(如果在开发环境已生成,可跳过)
python manage.py makemigrations
# 应用迁移
python manage.py migrate
```
2026-01-05 21:33:18 +08:00
4. **验证迁移结果**
- 检查应用是否正常运行
- 验证新功能是否可用
- 检查数据是否完整
2026-01-05 21:33:18 +08:00
#### 示例增加阅读笔记note字段
2026-01-05 21:33:18 +08:00
1. 在模型中添加字段(`core/models.py`
```python
# 正确的做法:设置为可空字段
note = models.TextField(blank=True, null=True, verbose_name="阅读笔记")
# 或者:提供默认值
note = models.TextField(default="", blank=True, verbose_name="阅读笔记")
```
2026-01-05 21:33:18 +08:00
2. 生成迁移文件:
```bash
python manage.py makemigrations
```
2026-01-05 21:33:18 +08:00
3. 检查迁移文件,确保新字段设置正确:
```python
# 迁移文件示例0003_readingrecord_note.py
class Migration(migrations.Migration):
dependencies = [
('core', '0002_xxx'),
]
operations = [
migrations.AddField(
model_name='readingrecord',
name='note',
field=models.TextField(blank=True, null=True, verbose_name='阅读笔记'),
),
]
```
2026-01-05 21:33:18 +08:00
4. 应用迁移:
```bash
python manage.py migrate
```
2026-01-05 21:33:18 +08:00
## CSV数据导入指南
### 生成CSV文件
项目包含一个`generate_import_csv.py`脚本用于生成符合数据库表结构的CSV文件并导入数据。
1. 生成CSV文件
```bash
python generate_import_csv.py
```
2. 生成的CSV文件
- `reading_type.csv` - 阅读记录类型
- `insight_record.csv` - 感悟记录
- `reading_record.csv` - 阅读记录
### CSV文件格式说明
#### reading_type.csv阅读记录类型
| 字段名 | 类型 | 说明 |
|-------|------|------|
| name | 字符串 | 阅读类型名称(如:书籍、文章、论文等) |
#### insight_record.csv感悟记录
| 字段名 | 类型 | 说明 |
|-------|------|------|
| date | 日期 | 记录日期格式YYYY-MM-DD |
| content | 文本 | 感悟内容 |
#### reading_record.csv阅读记录
| 字段名 | 类型 | 说明 |
|-------|------|------|
| date | 日期 | 记录日期格式YYYY-MM-DD |
| type_id | 整数 | 阅读类型ID关联reading_type表的id字段 |
| title | 字符串 | 阅读标题 |
| source | 字符串 | 阅读来源 |
| progress | 字符串 | 阅读进度(如:已完成、进行中、未开始) |
| note | 文本 | 阅读笔记 |
### 自定义CSV数据
你可以手动编辑生成的CSV文件添加或修改数据然后再次运行导入脚本将数据导入到数据库。
### 数据导入
脚本会自动将CSV数据导入到数据库中导入流程
1. 清空ReadingType表的现有数据避免类型ID冲突
2. 导入ReadingType数据
3. 导入InsightRecord数据
4. 导入ReadingRecord数据
### 验证导入结果
可以使用Django shell查询数据库验证数据是否正确导入
```bash
python -c "import os; os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'diary_family.settings'); import django; django.setup(); from core.models import ReadingType, InsightRecord, ReadingRecord; print('ReadingType数量:', ReadingType.objects.count()); print('InsightRecord数量:', InsightRecord.objects.count()); print('ReadingRecord数量:', ReadingRecord.objects.count()); print('ReadingType数据:', [rt.name for rt in ReadingType.objects.all()])"
```
## 生产部署
2026-01-04 19:21:52 +08:00
### 使用Gunicorn + Nginx
2026-01-04 19:21:52 +08:00
1. 安装Gunicorn
```bash
pip install gunicorn
```
2026-01-04 19:21:52 +08:00
2. 启动Gunicorn
2026-01-04 19:21:52 +08:00
```bash
gunicorn diary_family.wsgi:application --bind 0.0.0.0:8000
2026-01-04 19:21:52 +08:00
```
3. 配置Nginx`/etc/nginx/sites-available/diary-family`
```nginx
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /static/ {
alias /path/to/diary-family/static/;
}
location /media/ {
alias /path/to/diary-family/media/;
}
}
```
2026-01-04 19:21:52 +08:00
4. 启用Nginx配置
```bash
ln -s /etc/nginx/sites-available/diary-family /etc/nginx/sites-enabled/
systemctl restart nginx
```
2026-01-04 19:21:52 +08:00
## Redis服务器部署必需
家庭日报系统使用Celery进行异步任务处理如PDF生成、邮件发送而Celery依赖Redis作为消息代理和结果后端。**在生产环境中必须部署Redis服务器**。
### 1. 安装Redis服务器
在Ubuntu服务器上安装Redis
```bash
# 更新包管理器
sudo apt update
# 安装Redis服务器
sudo apt install redis-server -y
# 启动Redis服务
sudo systemctl start redis-server
# 设置Redis开机自启
sudo systemctl enable redis-server
# 检查Redis服务状态
sudo systemctl status redis-server
```
### 2. 配置Redis安全设置生产环境重要
编辑Redis配置文件以增强安全性
```bash
# 备份原始配置文件
sudo cp /etc/redis/redis.conf /etc/redis/redis.conf.backup
# 编辑Redis配置文件
sudo nano /etc/redis/redis.conf
```
在配置文件中进行以下修改:
```ini
# 1. 绑定到本地地址或特定IP禁止外部访问
bind 127.0.0.1
# 2. 设置强密码(强烈建议)
requirepass your_secure_password_here
# 3. 禁用危险命令(防止误操作)
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command CONFIG ""
# 4. 限制内存使用(根据服务器内存调整)
maxmemory 256mb
maxmemory-policy allkeys-lru
# 5. 启用持久化
save 900 1
save 300 10
save 60 10000
```
保存并重启Redis服务
```bash
# 重启Redis使配置生效
sudo systemctl restart redis-server
# 验证Redis是否正常运行
redis-cli ping
```
### 3. 测试Redis连接
验证Redis是否可以正常连接
#### 基本连接测试:
```bash
# 测试无密码连接(如果设置了密码,应该失败)
redis-cli ping
# 使用密码连接(应该成功)
redis-cli -a your_secure_password_here ping
# 测试基本操作
redis-cli -a your_secure_password_here set test_key "hello"
redis-cli -a your_secure_password_here get test_key
redis-cli -a your_secure_password_here del test_key
```
#### 高级测试:
```bash
# 测试Redis信息
redis-cli -a your_secure_password_here info
# 测试内存使用
redis-cli -a your_secure_password_here info memory
# 测试持久化状态
redis-cli -a your_secure_password_here info persistence
# 测试连接数
redis-cli -a your_secure_password_here info clients
# 性能测试设置100个键
for i in {1..100}; do redis-cli -a your_secure_password_here set "perf:$i" "value$i" > /dev/null; done
# 性能测试获取100个键
for i in {1..100}; do redis-cli -a your_secure_password_here get "perf:$i" > /dev/null; done
# 清理测试数据
for i in {1..100}; do redis-cli -a your_secure_password_here del "perf:$i" > /dev/null; done
```
#### 使用Python测试脚本
项目提供了专门的测试脚本可以全面测试Redis和Celery集成
```bash
# 运行完整的Redis和Celery测试
python test_redis_celery.py
# 测试输出示例:
# 2024-01-15 10:30:00 | INFO | 开始测试Redis连接...
# 2024-01-15 10:30:01 | SUCCESS | Redis连接测试通过
# 2024-01-15 10:30:02 | INFO | 开始测试Celery与Redis集成...
# 2024-01-15 10:30:03 | SUCCESS | Celery与Redis集成测试通过
# 2024-01-15 10:30:04 | INFO | 开始测试Redis性能...
# 2024-01-15 10:30:05 | SUCCESS | Redis性能优秀
# 2024-01-15 10:30:06 | SUCCESS | 所有测试通过生产环境Redis和Celery配置正确。
```
#### 快速验证命令:
```bash
# 一键验证Redis服务状态
sudo systemctl status redis-server --no-pager
# 验证Redis端口监听
sudo netstat -tlnp | grep 6379
# 验证Redis进程
ps aux | grep redis-server
# 验证Redis日志
sudo tail -n 10 /var/log/redis/redis-server.log
```
### 4. 配置Django项目使用Redis
在Django项目的`settings.py`更新Celery配置以使用Redis
```python
# 生产环境Redis配置带密码
CELERY_BROKER_URL = 'redis://:your_secure_password_here@localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://:your_secure_password_here@localhost:6379/0'
```
### 5. 验证Celery与Redis连接
测试Celery是否可以正常连接到Redis
```bash
# 激活虚拟环境
source /path/to/venv/bin/activate
# 测试Celery连接
celery -A diary_family inspect ping
# 查看Celery worker状态
celery -A diary_family status
# 查看任务队列
celery -A diary_family inspect active
celery -A diary_family inspect scheduled
```
### 6. Redis监控和维护
#### 监控Redis性能
```bash
# 查看Redis基本信息
redis-cli -a your_secure_password_here info
# 查看内存使用情况
redis-cli -a your_secure_password_here info memory
# 查看连接数
redis-cli -a your_secure_password_here info clients
# 查看持久化状态
redis-cli -a your_secure_password_here info persistence
```
#### 定期维护:
```bash
# 备份Redis数据
sudo cp /var/lib/redis/dump.rdb /backup/redis/dump.rdb.$(date +%Y%m%d)
# 清理过期键
redis-cli -a your_secure_password_here --scan --pattern "*" | xargs redis-cli -a your_secure_password_here del
# 查看慢查询日志
redis-cli -a your_secure_password_here slowlog get 10
```
### 7. Redis故障排除
#### 问题1Redis服务无法启动
```bash
# 查看Redis日志
sudo journalctl -u redis-server -f
# 检查配置文件语法
sudo redis-server /etc/redis/redis.conf --test
# 检查端口占用
sudo netstat -tlnp | grep 6379
```
#### 问题2连接被拒绝
```bash
# 检查防火墙设置
sudo ufw status
sudo ufw allow 6379/tcp
# 检查Redis绑定地址
sudo grep "^bind" /etc/redis/redis.conf
# 检查Redis是否在监听
sudo ss -tlnp | grep 6379
```
#### 问题3内存不足
```bash
# 查看内存使用情况
redis-cli -a your_secure_password_here info memory
# 清理过期数据
redis-cli -a your_secure_password_here memory purge
# 调整内存策略
# 编辑 /etc/redis/redis.conf 调整 maxmemory 和 maxmemory-policy
```
### 8. 生产环境优化建议
1. **使用独立Redis实例**为Celery专门配置一个Redis实例
2. **配置监控告警**使用Prometheus + Grafana监控Redis性能
3. **定期备份**设置定时任务备份Redis数据
4. **性能调优**:根据实际使用情况调整内存和连接数配置
5. **高可用方案**考虑使用Redis Sentinel或Redis Cluster
### 9. Redis部署常见问题解答FAQ
#### Q1: Redis是必须的吗可以用其他消息队列替代吗
**A**: 是的Redis是必须的。家庭日报系统使用Celery进行异步任务处理而Celery默认使用Redis作为消息代理。虽然可以使用RabbitMQ、Amazon SQS等其他消息队列但需要修改Celery配置和代码。Redis是最简单、性能最好的选择。
#### Q2: Redis应该安装在哪台服务器上
**A**: 建议的部署方案:
1. **小型部署**Redis和Django应用安装在同一台服务器上推荐初学者
2. **中型部署**Redis安装在与Django应用不同的服务器上但在同一内网
3. **生产部署**使用Redis集群或云Redis服务如AWS ElastiCache、Azure Cache for Redis
#### Q3: Redis需要多少内存
**A**: 内存需求取决于使用情况:
- **最小配置**: 256MB适合小型家庭使用
- **推荐配置**: 1GB适合常规使用有增长空间
- **生产配置**: 2GB+(适合多用户或高频任务)
#### Q4: 如何设置Redis密码
**A**: 在 `/etc/redis/redis.conf` 中设置:
```ini
requirepass your_strong_password_here
```
然后在Django的 `settings.py` 中更新:
```python
CELERY_BROKER_URL = 'redis://:your_strong_password_here@localhost:6379/0'
```
#### Q5: Redis数据会丢失吗
**A**: Redis默认将数据存储在内存中重启服务会丢失数据。但可以通过配置持久化来避免
```ini
# 在redis.conf中启用持久化
save 900 1 # 900秒内至少有1个键被修改
save 300 10 # 300秒内至少有10个键被修改
save 60 10000 # 60秒内至少有10000个键被修改
```
#### Q6: 如何监控Redis性能
**A**: 使用以下命令监控:
```bash
# 实时监控
redis-cli -a your_password monitor
# 查看统计信息
redis-cli -a your_password info
# 查看慢查询
redis-cli -a your_password slowlog get 10
```
#### Q7: Celery任务堆积怎么办
**A**: 处理步骤:
1. 增加worker数量`celery -A diary_family worker --concurrency=4 -l info`
2. 优化任务代码,减少执行时间
3. 使用优先级队列
4. 监控Redis内存使用防止内存不足
#### Q8: 如何备份Redis数据
**A**: 备份方法:
```bash
# 手动备份
sudo cp /var/lib/redis/dump.rdb /backup/redis/dump.rdb.$(date +%Y%m%d)
# 自动备份添加到crontab
0 2 * * * sudo cp /var/lib/redis/dump.rdb /backup/redis/dump.rdb.$(date +\%Y\%m\%d)
```
#### Q9: Redis连接数过多怎么办
**A**: 解决方法:
1. 增加最大连接数在redis.conf中
```ini
maxclients 10000
```
2. 优化Celery连接池
3. 检查是否有连接泄漏
#### Q10: 如何验证Redis部署是否成功
**A**: 使用项目提供的测试脚本:
```bash
# 运行完整测试
python test_redis_celery.py
# 预期输出:所有测试通过,显示绿色成功信息
```
#### Q11: 生产环境Redis安全注意事项
**A**: 安全配置清单:
- [x] 设置强密码
- [x] 绑定到127.0.0.1或内网IP
- [x] 禁用危险命令FLUSHALL, FLUSHDB, CONFIG
- [x] 启用防火墙,只允许必要端口
- [x] 定期更新Redis版本
- [x] 配置日志监控
#### Q12: Redis性能调优参数有哪些
**A**: 关键调优参数:
```ini
# 内存管理
maxmemory 1gb
maxmemory-policy allkeys-lru
# 持久化优化
save 900 1
save 300 10
save 60 10000
# 网络优化
tcp-keepalive 60
timeout 300
```
2026-01-07 21:37:18 +08:00
## 常规代码更新流程
当需要更新代码时,可以使用以下命令:
2026-01-07 21:37:18 +08:00
```bash
# 退出虚拟环境
deactivate
# 切换到项目目录
2026-01-07 21:37:18 +08:00
cd /var/www/diary-family
# 1. 拉取远程最新代码(只获取,不合并)
git fetch origin
# 2. 硬重置本地分支到远程分支的最新版本(会覆盖所有本地未提交修改)
# 注意:将 main 替换为你的分支名(如 master、dev 等)
git reset --hard origin/main
# 3. 激活虚拟环境
source venv/bin/activate
# 4. 安装新依赖(如果有)
pip install -r requirements.txt
# 5. 收集静态文件(如果有静态文件更新)
python manage.py collectstatic --noinput
# 6. 重启服务
sudo supervisorctl restart all
sudo systemctl restart nginx
```
## 系统配置
2026-01-04 19:21:52 +08:00
在系统配置页面可以设置:
- SMTP服务器信息
- 邮件发送时间
- 收件人邮箱
2026-01-04 19:21:52 +08:00
## Celery 定时发送邮件任务配置
### 1. 邮件配置设置
在系统配置页面设置完邮件信息后,还需要在 Django 项目的 settings.py 中添加基础邮件配置:
```python
# 邮件基础配置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_PORT = 587 # 或根据你的 SMTP 服务器设置
EMAIL_USE_TLS = True # 或根据你的 SMTP 服务器设置
```
### 2. 启动 Celery Worker 和 Beat
#### 开发环境
```bash
# 启动 Celery Worker
celery -A diary_family worker -l info
# 启动 Celery Beat用于定时任务调度
celery -A diary_family beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler
```
#### 生产环境
建议使用 supervisor 管理 Celery 进程。创建两个 supervisor 配置文件:
1. **celery_worker.conf**
```ini
[program:celery_worker]
command=/path/to/venv/bin/celery -A diary_family worker -l info
directory=/path/to/diary-family
user=www-data
group=www-data
autostart=true
autorestart=true
stdout_logfile=/var/log/celery/worker.log
stderr_logfile=/var/log/celery/worker_error.log
```
2. **celery_beat.conf**
```ini
[program:celery_beat]
command=/path/to/venv/bin/celery -A diary_family beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler
directory=/path/to/diary-family
user=www-data
group=www-data
autostart=true
autorestart=true
stdout_logfile=/var/log/celery/beat.log
stderr_logfile=/var/log/celery/beat_error.log
```
启动 supervisor 服务:
```bash
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start celery_worker
sudo supervisorctl start celery_beat
```
### 3. 配置定时任务
系统使用 `django_celery_beat` 进行定时任务管理,支持两种方式配置:
#### 方式一:通过 Django 管理后台(推荐)
1. 登录 Django 管理后台(/houtai
2. 找到 **Periodic tasks**(周期性任务)
3. 点击 **Add** 按钮添加新任务
4. 配置任务:
- **Name**: 任务名称(如:每日报告发送)
- **Task (registered)**: 选择 `core.tasks.send_daily_report`
- **Interval**: 设置执行间隔(如:每天)
- **Enabled**: 勾选启用
5. 点击 **Save** 保存
#### 方式二:通过代码配置
`core/tasks.py` 中添加定时任务配置:
```python
from celery import shared_task
from django_celery_beat.models import PeriodicTask, IntervalSchedule
# 创建或更新定时任务
def setup_daily_report_task():
# 创建每天执行的间隔
schedule, created = IntervalSchedule.objects.get_or_create(
every=1,
period=IntervalSchedule.DAYS,
)
# 创建或更新定时任务
task, created = PeriodicTask.objects.update_or_create(
name='Daily Report Task',
defaults={
'interval': schedule,
'task': 'core.tasks.send_daily_report',
},
)
return task
```
然后在 Django 启动时调用此函数(如在 `core/apps.py` 中)。
### 4. 验证任务执行
- 查看 Celery 日志:`tail -f /var/log/celery/worker.log`
- 检查邮件是否正常发送
- 在 Django 管理后台查看任务执行记录
2026-01-10 18:08:34 +08:00
### 5. 日志文件不存在问题解决方法
如果在生产服务器上执行 `tail -f /var/log/celery/worker.log` 时提示 `No such file or directory`,请按照以下步骤解决:
#### 步骤1检查日志目录是否存在
```bash
# 检查日志目录是否存在
ls -la /var/log/celery/
# 如果目录不存在,创建目录
sudo mkdir -p /var/log/celery/
# 设置正确的权限(确保 Celery 进程用户有读写权限)
sudo chown -R www-data:www-data /var/log/celery/
sudo chmod -R 755 /var/log/celery/
```
#### 步骤2检查 Supervisor 配置
确保 Supervisor 配置文件中指定的日志路径正确,并且 Celery 进程用户对该路径有读写权限。
#### 步骤3重启 Supervisor 和 Celery
```bash
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl restart celery_worker celery_beat
```
### 5.1 日志文件查看指南
在生产环境中,有多种日志来源,了解每种日志的位置和查看方法非常重要:
#### 5.1.1 Celery Worker 和 Beat 日志
这些日志由 Celery 进程产生,需要先创建日志目录:
```bash
# 创建日志目录
sudo mkdir -p /var/log/celery/
# 设置权限
sudo chown -R www-data:www-data /var/log/celery/
sudo chmod -R 755 /var/log/celery/
```
查看日志:
```bash
# 实时查看 Worker 日志
tail -f /var/log/celery/worker.log
# 实时查看 Beat 日志
tail -f /var/log/celery/beat.log
# 查看最近50行
tail -n 50 /var/log/celery/worker.log
# 搜索错误信息
grep -i error /var/log/celery/worker.log
# 搜索特定任务
grep -i "generate_daily_pdf_report" /var/log/celery/worker.log
```
#### 5.1.2 测试脚本日志
运行测试脚本时,日志会同时输出到控制台和文件:
```bash
# 运行测试脚本(输出到控制台)
python test_redis_celery.py
# 查看测试日志文件
tail -f /var/log/celery/test_redis_celery.log
# 运行测试并保存到文件
python test_redis_celery.py 2>&1 | tee /var/log/celery/test_output.log
```
测试脚本日志内容示例:
```
2024-01-15 10:30:00 | INFO | 开始测试Redis连接...
2024-01-15 10:30:01 | SUCCESS | Redis连接测试通过
2024-01-15 10:30:02 | INFO | 开始测试Celery与Redis集成...
2024-01-15 10:30:03 | SUCCESS | Celery与Redis集成测试通过
```
#### 5.1.3 Redis 日志
Redis 的日志通常在系统日志中:
```bash
# 查看 Redis 系统日志
sudo journalctl -u redis-server -f
# 查看 Redis 错误日志
sudo tail -f /var/log/redis/redis-server.log
# 查看所有 Redis 相关日志
sudo grep -i redis /var/log/syslog
```
#### 5.1.4 Django 应用日志
```bash
# 查看 Django 应用日志
tail -f /path/to/diary-family/logs/app.log
# 查看 Gunicorn 日志
sudo tail -f /var/log/gunicorn/access.log
sudo tail -f /var/log/gunicorn/error.log
```
#### 5.1.5 Nginx 日志
```bash
# 查看访问日志
sudo tail -f /var/log/nginx/access.log
# 查看错误日志
sudo tail -f /var/log/nginx/error.log
```
#### 5.1.6 综合日志查看脚本
创建一个综合日志查看脚本:
```bash
#!/bin/bash
# save as: /usr/local/bin/view-all-logs
echo "=== Celery Worker Log ==="
tail -n 20 /var/log/celery/worker.log
echo -e "\n=== Celery Beat Log ==="
tail -n 20 /var/log/celery/beat.log
echo -e "\n=== Redis Server Log ==="
sudo tail -n 20 /var/log/redis/redis-server.log
echo -e "\n=== Nginx Error Log ==="
sudo tail -n 20 /var/log/nginx/error.log
```
使用方法:
```bash
# 给脚本添加执行权限
sudo chmod +x /usr/local/bin/view-all-logs
# 运行脚本
view-all-logs
```
#### 5.1.7 日志轮转配置
为防止日志文件过大,配置日志轮转:
创建 `/etc/logrotate.d/celery-app`
```
/var/log/celery/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 www-data www-data
sharedscripts
postrotate
supervisorctl restart celery_worker celery_beat > /dev/null 2>&1 || true
endscript
}
```
启用配置:
```bash
sudo logrotate -f /etc/logrotate.d/celery-app
```
#### 5.1.8 日志查看常见问题
**问题1日志文件权限被拒绝**
```bash
# 检查权限
ls -la /var/log/celery/
# 如果权限不对,重新设置
sudo chown -R www-data:www-data /var/log/celery/
sudo chmod -R 755 /var/log/celery/
```
**问题2日志文件不存在**
```bash
# 检查目录是否存在
ls -la /var/log/ | grep celery
# 如果不存在,创建目录
sudo mkdir -p /var/log/celery/
sudo chown www-data:www-data /var/log/celery/
```
**问题3日志不更新**
```bash
# 检查进程是否运行
ps aux | grep celery
# 检查文件是否被锁定
sudo lsof /var/log/celery/worker.log
# 检查磁盘空间
df -h /var/log/
```
**问题4如何清理旧日志**
```bash
# 删除7天前的日志
find /var/log/celery/ -name "*.log.*.gz" -mtime +7 -delete
# 清空当前日志文件(谨慎使用)
sudo truncate -s 0 /var/log/celery/worker.log
```
2026-01-10 18:08:34 +08:00
### 6. 试运行周期任务
当设置一个周期任务后,您可以通过以下方式试运行任务,而不需要等待到指定的时间:
#### 方式1通过 Django 管理后台
1. 登录 Django 管理后台(/houtai
2. 找到 **Periodic tasks**(周期性任务)
3. 选择您创建的任务
4. 点击页面底部的 **Run Task** 按钮立即执行任务
#### 方式2通过命令行
```bash
# 直接调用任务函数(同步执行)
python manage.py shell -c "from core.tasks import generate_daily_pdf_report; generate_daily_pdf_report()"
# 或者使用 Celery 命令行工具
celery -A diary_family call core.tasks.generate_daily_pdf_report
```
#### 方式3使用测试脚本
项目提供了多个测试脚本,用于验证不同功能:
2026-01-10 18:08:34 +08:00
1. **Celery任务测试**
```bash
# 测试Celery任务执行
python test_celery.py
```
2. **Redis和Celery集成测试**(生产环境推荐):
```bash
# 测试Redis连接、Celery集成和性能
python test_redis_celery.py
```
3. **Redis连接测试**(快速验证):
```bash
# 仅测试Redis连接
python -c "import redis; r = redis.Redis(host='localhost', port=6379); print('Redis连接成功' if r.ping() else '连接失败')"
```
2026-01-10 18:08:34 +08:00
### 7. 常见错误和解决方法
#### 错误1日志文件不存在
**错误信息**`tail: cannot open '/var/log/celery/worker.log' for reading: No such file or directory`
**解决方法**
- 按照步骤5中的说明创建日志目录并设置正确权限
- 检查 Supervisor 配置中的日志路径是否正确
- 重启 Supervisor 和 Celery 服务
#### 错误2Celery 无法连接到 Redis
**错误信息**`redis.exceptions.ConnectionError: Error 111 connecting to localhost:6379. Connection refused.`
**解决方法**
1. **检查Redis服务状态**
```bash
sudo systemctl status redis-server
```
2. **如果Redis未运行启动服务**
```bash
sudo systemctl start redis-server
sudo systemctl enable redis-server
```
3. **检查Redis配置**
- 确保Redis配置文件 `/etc/redis/redis.conf``bind` 设置为 `127.0.0.1`
- 检查是否有防火墙阻止连接:`sudo ufw status`
- 检查端口是否被占用:`sudo netstat -tlnp | grep 6379`
4. **测试Redis连接**
```bash
# 测试基本连接
redis-cli ping
# 如果设置了密码,使用密码连接
redis-cli -a your_password ping
```
5. **检查Celery配置**
- 确保 `settings.py` 中的 `CELERY_BROKER_URL``CELERY_RESULT_BACKEND` 配置正确
- 如果Redis有密码URL格式应为`redis://:password@localhost:6379/0`
6. **详细排查**
- 查看Redis日志`sudo journalctl -u redis-server -f`
- 查看Celery日志`tail -f /var/log/celery/worker.log`
- 参考 [Redis服务器部署](#redis服务器部署必需) 章节进行完整配置
**注意**:如果这是新部署的环境,请确保已按照 [Redis服务器部署](#redis服务器部署必需) 章节完整安装和配置Redis。
2026-01-10 18:08:34 +08:00
#### 错误3任务执行失败
**错误信息**`Task core.tasks.generate_daily_pdf_report[xxx] raised unexpected: Exception(...)`
**解决方法**
- 查看详细日志:`tail -f /var/log/celery/worker.log`
- 检查任务代码中的错误
- 确保所有依赖库都已正确安装
- 检查相关服务如数据库、Redis是否正常运行
#### 错误4PDF 生成失败
**错误信息**`WeasyPrint库不可用无法生成PDF报告`
**解决方法**
- 安装 WeasyPrint 库:`pip install weasyprint`
- 对于 Ubuntu 系统,可能需要安装系统依赖:
```bash
sudo apt-get install -y libpango-1.0-0 libpangoft2-1.0-0
```
### 8. 常见问题排查
1. **任务不执行**
- 检查 Celery worker 和 beat 是否正常运行
- 检查 Redis 服务是否正常
- 检查任务是否已启用
- 检查系统时间是否正确
2. **邮件发送失败**
- 检查 SMTP 服务器配置是否正确
- 检查邮箱账号密码是否正确
- 检查收件人邮箱格式是否正确
- 查看 Celery 日志中的错误信息
3. **任务执行延迟**
- 检查系统负载是否过高
- 考虑增加 Celery worker 数量
- 检查 Redis 性能
### 6. 生产环境优化建议
#### Redis相关优化
1. **使用独立Redis实例**为Celery专门配置一个Redis实例避免与其他应用共享
2. **Redis性能调优**
- 根据服务器内存调整 `maxmemory` 配置
- 使用合适的内存淘汰策略(如 `allkeys-lru`
- 启用持久化确保数据安全
3. **Redis监控**
- 配置Prometheus + Grafana监控Redis性能
- 设置内存使用告警
- 监控连接数和慢查询
#### Celery相关优化
1. **Worker配置**
- 配置合适的worker数量建议CPU核心数 × 2
- 使用prefork或gevent模式根据任务类型选择
- 设置合理的任务超时时间
2. **任务管理**
- 定期清理Celery任务结果
- 配置任务重试机制
- 使用任务优先级队列
3. **监控工具**
- 启用Celery监控工具如Flower
- 配置任务执行统计
- 设置任务失败告警
#### 系统级优化:
1. **资源隔离**为Celery worker和Redis分配独立的系统资源
2. **日志管理**配置集中式日志收集如ELK Stack
3. **备份策略**定期备份Redis数据和任务结果
4. **高可用方案**考虑使用Redis Sentinel或Redis Cluster实现高可用
## 定时生成PDF文件配置
除了定时发送邮件外系统还支持单独定时生成PDF文件便于在服务器上保存历史报告。
### 1. 配置定时生成PDF任务
#### 方式一:通过 Django 管理后台(推荐)
1. 登录 Django 管理后台(/houtai
2. 找到 **Periodic tasks**(周期性任务)
3. 点击 **Add** 按钮添加新任务
4. 配置任务:
- **Name**: 任务名称每日PDF报告生成
- **Task (registered)**: 选择 `core.tasks.generate_daily_pdf_report`
- **Interval**: 设置执行间隔(如:每天)
- **Enabled**: 勾选启用
5. 点击 **Save** 保存
#### 方式二:通过代码配置
`core/tasks.py` 中添加定时任务配置:
```python
from celery import shared_task
from django_celery_beat.models import PeriodicTask, IntervalSchedule
# 创建或更新PDF生成定时任务
def setup_daily_pdf_task():
# 创建每天执行的间隔
schedule, created = IntervalSchedule.objects.get_or_create(
every=1,
period=IntervalSchedule.DAYS,
)
# 创建或更新定时任务
task, created = PeriodicTask.objects.update_or_create(
name='Daily PDF Generation Task',
defaults={
'interval': schedule,
'task': 'core.tasks.generate_daily_pdf_report',
},
)
return task
```
然后在 Django 启动时调用此函数(如在 `core/apps.py` 中)。
### 2. PDF文件存储位置
生成的PDF文件默认存储在项目的 `reports` 目录下,命名格式为 `report_YYYY-MM-DD.pdf`
可以在 `settings.py` 中修改存储位置:
```python
# Reports files configuration
REPORTS_URL = '/reports/'
REPORTS_ROOT = BASE_DIR / 'reports' # 可以修改为其他路径
```
### 3. 验证PDF生成任务
- 查看 Celery 日志:`tail -f /var/log/celery/worker.log`
- 检查PDF文件是否生成`ls -la /path/to/diary-family/reports/`
- 在 Django 管理后台查看任务执行记录
### 4. 常见问题排查
1. **PDF生成失败**
- 检查 WeasyPrint 库是否正确安装:`pip list | grep weasyprint`
- 检查系统字体是否完整PDF生成需要系统字体支持
- 查看 Celery 日志中的错误信息
2. **任务执行但没有生成文件**
- 检查 `REPORTS_ROOT` 目录权限:确保 Celery 进程有写入权限
- 检查磁盘空间是否充足
- 查看 Celery 日志中的详细信息
3. **PDF内容不完整**
- 检查模板文件 `core/templates/core/report_pdf.html` 是否完整
- 确保所有依赖的 CSS 和图像资源都能正常访问
## 邮件功能测试
项目提供了两个专门的测试脚本,用于验证邮件发送功能是否正常工作:
### 1. 基础邮件测试test_email.py
用于测试直接邮件发送功能验证SMTP配置是否正确。
#### 测试内容
- ✅ 邮件配置验证
- ✅ SMTP连接测试
- ✅ 发送简单文本邮件
- ✅ 发送HTML邮件带附件
- ✅ 邮件发送性能测试
#### 运行方式
```bash
# 运行基础邮件测试
python test_email.py
```
#### 测试结果说明
- 所有测试通过:邮件系统配置正确,可以正常工作
- 3项以上通过邮件系统基本可用部分功能可能需要优化
- 少于3项通过邮件系统存在严重问题需要检查配置
### 2. Celery异步邮件测试test_celery_email.py
用于测试通过Celery异步发送邮件的功能验证整个异步任务链是否正常。
#### 测试内容
- ✅ Celery邮件配置验证
- ✅ Celery Worker状态检查
- ✅ Celery异步邮件任务执行
- ✅ 同步发送测试邮件(用于对比)
#### 运行方式
```bash
# 运行Celery异步邮件测试
python test_celery_email.py
```
#### 测试结果说明
- 所有测试通过Celery邮件功能正常
- 2项以上通过Celery邮件功能基本可用
- 少于2项通过存在严重问题需要检查配置
### 3. 常见问题排查
#### 测试失败时的检查步骤
1. **检查SMTP配置**
```bash
# 查看Django邮件配置
python -c "import os; os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'diary_family.settings'); import django; django.setup(); from django.conf import settings; print('EMAIL_HOST:', getattr(settings, 'EMAIL_HOST', None)); print('EMAIL_PORT:', getattr(settings, 'EMAIL_PORT', None)); print('EMAIL_HOST_USER:', getattr(settings, 'EMAIL_HOST_USER', None))"
```
2. **检查Redis服务**
```bash
sudo systemctl status redis-server
redis-cli ping
```
3. **检查Celery Worker状态**
```bash
# 查看Celery Worker状态
celery -A diary_family status
# 如果Worker未运行启动它
celery -A diary_family worker -l info
```
4. **查看日志文件**
```bash
# 查看邮件测试日志
tail -f /var/log/celery/test_email.log
tail -f /var/log/celery/test_celery_email.log
# 查看Celery日志
tail -f /var/log/celery/worker.log
tail -f /var/log/celery/beat.log
```
5. **验证网络连通性**
```bash
# 测试SMTP服务器连通性
telnet smtp.example.com 587
# 测试DNS解析
nslookup smtp.example.com
```
#### 常见错误及解决方案
| 错误信息 | 可能原因 | 解决方案 |
|---------|---------|---------|
| 连接被拒绝 | SMTP服务器地址/端口错误 | 检查SMTP配置确认服务器地址和端口 |
| 认证失败 | 用户名或密码错误 | 检查邮箱账号和密码确认是否开启了SMTP服务 |
| Celery连接失败 | Redis未运行或配置错误 | 检查Redis服务状态验证CELERY_BROKER_URL配置 |
| 任务超时 | Worker未运行或任务执行时间过长 | 启动Celery Worker检查任务代码 |
## Celery 监控(可选)
使用 Flower 监控 Celery 任务:
```bash
# 安装 Flower
pip install flower
# 启动 Flower
celery -A diary_family flower --port=5555
```
访问 http://your-server:5555 查看任务监控界面。
## RPA/自动化脚本 CSRF保护问题解决方案
当使用RPA机器人流程自动化或自动化脚本调用系统API时可能会遇到Django的CSRF跨站请求伪造保护机制拦截的问题。
### 问题现象
- 调用API返回 **403 Forbidden** 错误
- 错误信息包含 `CSRF verification failed``Forbidden (CSRF cookie not set.)`
- RPA工具无法正常提交数据到 `/api/v1/summary/submit/`
### 问题原因
Django默认启用CSRF保护中间件`CsrfViewMiddleware`所有POST请求都需要提供有效的CSRF令牌。但自动化脚本和RPA工具无法像浏览器一样获取和携带CSRF令牌。
### 解决方案
#### 方案一为API视图添加CSRF豁免推荐
修改 `core/views.py` 文件为API提交接口添加 `@csrf_exempt` 装饰器:
```python
from django.views.decorators.csrf import csrf_exempt
# 在 api_submit_summary 函数前添加装饰器
@csrf_exempt
def api_submit_summary(request):
"""API提交汇总记录 - 仅接受指定分类和发言人的记录"""
# ... 原有代码保持不变 ...
```
**操作步骤**
1. 打开 `core/views.py` 文件
2. 确保文件顶部已导入 `csrf_exempt`
```python
from django.views.decorators.csrf import csrf_exempt
```
3.`api_submit_summary` 函数定义前添加 `@csrf_exempt` 装饰器
4. 保存文件并重启Gunicorn服务
```bash
sudo supervisorctl restart diary-family
# 或
sudo systemctl restart gunicorn
```
#### 方案二配置CSRF信任域名
如果不想完全禁用CSRF保护可以在 `settings.py` 中配置信任的域名:
```python
# 在 settings.py 中添加
CSRF_TRUSTED_ORIGINS = [
'https://your-domain.com',
'https://*.your-domain.com',
]
# 如果使用IP访问添加IP地址
CSRF_TRUSTED_ORIGINS = [
'http://192.168.1.100',
'http://localhost',
]
```
#### 方案三为特定URL路径禁用CSRF
`core/views.py` 中创建一个通用的API装饰器
```python
from django.views.decorators.csrf import csrf_exempt
from functools import wraps
def api_exempt(view_func):
"""
API接口CSRF豁免装饰器
用于标记不需要CSRF保护的API接口
"""
@wraps(view_func)
@csrf_exempt
def wrapped_view(request, *args, **kwargs):
# 可以在这里添加API认证逻辑
return view_func(request, *args, **kwargs)
return wrapped_view
# 使用方式
@api_exempt
def api_submit_summary(request):
# ... 原有代码 ...
```
### 安全建议
1. **仅对必要的API接口禁用CSRF保护**,不要对整个视图或应用禁用
2. **添加API认证机制**如API Key、Token认证替代CSRF保护
3. **限制API访问来源IP**在Nginx或防火墙层面进行限制
4. **使用HTTPS协议**确保数据传输安全
5. **记录API访问日志**,便于审计和排查问题
### 验证修复
修改配置后使用以下命令验证API是否可正常访问
```bash
# 测试API接口
curl -X POST http://your-server/api/v1/summary/submit/ \
-d "content=测试内容"
# 预期返回
{"success": true, "message": "提交成功", "id": 123}
```
### 常见问题
#### Q1: 添加 `@csrf_exempt` 后是否安全?
**A**: 对于内部API和自动化脚本调用的接口添加 `@csrf_exempt` 是安全的,因为:
- API接口通常需要其他形式的认证如API Key
- 自动化脚本运行在受控环境中
- 可以结合IP白名单、请求频率限制等安全措施
#### Q2: 如何在RPA工具中处理CSRF
**A**: 推荐在服务器端禁用CSRF保护方案一而不是在RPA工具中处理CSRF令牌。这样可以简化RPA脚本的复杂度。
#### Q3: 修改后需要重启服务吗?
**A**: 是的Python代码修改后需要重启Gunicorn或uWSGI服务才能生效
```bash
sudo supervisorctl restart all
# 或
sudo systemctl restart gunicorn
```
---
---
## API接口文档
系统提供RESTful API接口支持外部客户端提交汇总记录和临时文件。
### 1. 汇总记录提交API
用于外部客户端(如监控脚本、自动化任务)向系统提交汇总记录。
#### 请求信息
- **URL**: `/api/v1/summary/submit/`
- **方法**: `POST`
- **Content-Type**: `application/x-www-form-urlencoded``multipart/form-data`
#### 请求参数
| 参数名 | 类型 | 必填 | 说明 |
|-------|------|------|------|
| content | string | 是 | 汇总记录内容,最大长度不限 |
| source | string | 否 | 来源自动获取客户端主机名和IP |
#### 响应格式
**成功响应** (HTTP 200):
```json
{
"success": true,
"message": "提交成功",
"id": 123
}
```
**失败响应** (HTTP 400/500):
```json
{
"success": false,
"message": "错误信息描述"
}
```
#### 调用示例
```bash
# 使用 curl 提交汇总记录
curl -X POST http://your-server/api/v1/summary/submit/ \
-d "content=这是自动提交的汇总内容"
# Python requests 调用示例
import requests
url = "http://your-server/api/v1/summary/submit/"
data = {
"content": "监控报告:系统运行正常"
}
response = requests.post(url, data=data)
result = response.json()
print(result)
```
#### 注意事项
1. **数据验证**API仅接受以下条件的记录
- 分类必须为"定期"
- 发言人必须为"机器人"
- 内容不能为空
2. **来源自动生成**系统会自动获取客户端的主机名和IP地址填充到source字段。
3. **日期自动设置**:记录日期自动设置为提交时的日期。
---
### 2. 临时文件上传API
用于上传临时文件到公开内容支持1小时/1天/7天过期自动删除。
#### 请求信息
- **URL**: `/api/v1/temp-upload/`
- **方法**: `POST`
- **Content-Type**: `multipart/form-data`
- **文件大小限制**: 500MB
#### 请求参数
| 参数名 | 类型 | 必填 | 说明 |
|-------|------|------|------|
| title | string | 是 | 文件标题 |
| file | file | 是 | 上传的文件最大500MB |
| expire_type | string | 是 | 过期时间:`expire_1h`(1小时) / `expire_1d`(1天) / `expire_7d`(7天) |
#### 响应格式
**成功响应** (HTTP 200):
```json
{
"success": true,
"message": "上传成功",
"id": 1,
"file_url": "http://your-server/media/public_files/xxx.pdf",
"file_name": "document.pdf",
"file_size": 1048576,
"expire_at": "2026-05-25T18:30:00Z",
"expire_type": "expire_1d"
}
```
**失败响应** (HTTP 400/500):
```json
{
"success": false,
"message": "错误信息描述"
}
```
#### 调用示例
```bash
# 使用 curl 上传文件
curl -X POST http://your-server/api/v1/temp-upload/ \
-F "file=@document.pdf" \
-F "title=测试文件" \
-F "expire_type=expire_1d"
# Python requests 调用示例
import requests
url = "http://your-server/api/v1/temp-upload/"
files = {'file': open('document.pdf', 'rb')}
data = {
'title': '测试文件',
'expire_type': 'expire_1d'
}
response = requests.post(url, files=files, data=data)
result = response.json()
print(result)
```
---
### 3. 临时发言(页面表单)
在公开内容页面 `/public/` 提供临时留言功能。
#### 功能说明
- 用户名可选最大20字节
- 内容必填最大1000字节
- 留言保留时间10分钟
- 显示用户名可选、内容、时间、来源IP
#### 提交方式
`/public/` 页面直接填写表单提交无需API调用。
#### 显示规则
- 只显示10分钟内的留言
- 过期后自动从页面移除
- 后台定时任务定期清理过期数据
---
### 4. 初始化必需数据
在使用API提交汇总记录前需要确保数据库中存在以下数据
#### 方法一Django Shell初始化
```bash
python manage.py shell -c "
from core.models import SummaryCategory, FamilyMember
# 创建'定期'分类(如果不存在)
category, created = SummaryCategory.objects.get_or_create(name='定期')
if created:
print('创建分类: 定期')
else:
print('分类已存在: 定期')
# 创建'机器人'发言人(如果不存在)
speaker, created = FamilyMember.objects.get_or_create(name='机器人')
if created:
print('创建发言人: 机器人')
else:
print('发言人已存在: 机器人')
print('初始化完成')
"
```
#### 方法二Django Admin后台创建
1. 登录后台管理:`/houtai`
2.**汇总分类** 中添加名为"定期"的分类
3.**家庭成员** 中添加名为"机器人"的成员
---
### 5. 常见问题排查
#### 问题1提交返回"分类 '定期' 不存在"
**解决方法**:在数据库中创建该分类(见上方初始化方法)
#### 问题2提交返回"发言人 '机器人' 不存在"
**解决方法**:在数据库中创建该发言人(见上方初始化方法)
#### 问题3上传返回"内容不能为空"
**解决方法**:确保请求中包含 `content` 参数且不为空
#### 问题4返回HTTP 405错误
**解决方法**确认使用的是POST方法不是GET方法
#### 问题5文件上传失败413 Request Entity Too Large
**解决方法**检查nginx配置中的 `client_max_body_size` 是否大于500m
```nginx
# 在 /etc/nginx/sites-enabled/diary_family 中添加
client_max_body_size 500m;
```
## Fail2ban 登录保护配置
为了防止暴力破解登录密码,系统集成了 Fail2ban 自动封禁功能。当用户在短时间内多次登录失败时,其 IP 地址将被自动封禁。
### 工作原理
1. **日志记录**:登录失败时,系统会记录包含 IP 地址的警告日志到 syslog 和 `logs/auth.log`
2. **Fail2ban 监控**Fail2ban 实时监控日志文件,检测登录失败事件
3. **自动封禁**:当同一 IP 在指定时间内失败次数超过阈值时,自动封禁该 IP
### 安装 Fail2ban
在 Ubuntu 服务器上安装 Fail2ban
```bash
# 更新包管理器
sudo apt update
# 安装 Fail2ban
sudo apt install fail2ban -y
# 启动 Fail2ban 服务
sudo systemctl start fail2ban
# 设置开机自启
sudo systemctl enable fail2ban
# 检查服务状态
sudo systemctl status fail2ban
```
### 配置 Fail2ban
#### 1. 复制过滤器配置
```bash
# 创建过滤器目录(如果不存在)
sudo mkdir -p /etc/fail2ban/filter.d
# 复制过滤器配置
sudo cp /var/www/diary-family/deploy/fail2ban/filter.d/diary-family.conf /etc/fail2ban/filter.d/
# 验证过滤器配置
sudo fail2ban-client -t
```
#### 2. 复制监狱配置
```bash
# 创建监狱配置目录(如果不存在)
sudo mkdir -p /etc/fail2ban/jail.d
# 复制监狱配置
sudo cp /var/www/diary-family/deploy/fail2ban/jail.d/diary-family.conf /etc/fail2ban/jail.d/
# 编辑配置(根据实际需求修改)
sudo nano /etc/fail2ban/jail.d/diary-family.conf
```
#### 3. 关键配置参数说明
| 参数 | 默认值 | 说明 |
|-----|-------|------|
| `maxretry` | 5 | 触发封禁前的最大失败次数 |
| `bantime` | 3600 | 封禁时间默认1小时 |
| `findtime` | 600 | 检测时间窗口默认10分钟 |
| `ignoreip` | 127.0.0.1 | 白名单IP不会被封禁 |
#### 4. 重启 Fail2ban 服务
```bash
# 重新加载配置
sudo systemctl restart fail2ban
# 或者使用 fail2ban-client
sudo fail2ban-client reload
```
### 验证配置
#### 1. 检查 Fail2ban 状态
```bash
# 查看整体状态
sudo fail2ban-client status
# 查看 diary-family 监狱状态
sudo fail2ban-client status diary-family
# 查看被封禁的IP列表
sudo fail2ban-client status diary-family | grep "Banned IP list"
```
#### 2. 测试登录失败检测
```bash
# 手动测试过滤器(使用最近的日志)
sudo fail2ban-regex /var/log/syslog /etc/fail2ban/filter.d/diary-family.conf
# 或者测试 auth.log
sudo fail2ban-regex /var/www/diary-family/logs/auth.log /etc/fail2ban/filter.d/diary-family.conf
```
#### 3. 查看日志
```bash
# 查看 Fail2ban 日志
sudo tail -f /var/log/fail2ban.log
# 查看系统日志中的认证失败
sudo grep "Authentication failure" /var/log/syslog
# 查看 Django 认证日志
tail -f /var/www/diary-family/logs/auth.log
```
### 手动管理封禁
#### 解封 IP 地址
```bash
# 手动解封某个 IP
sudo fail2ban-client set diary-family unbanip 192.168.1.100
# 解封所有 IP
sudo fail2ban-client set diary-family unbanip --all
```
#### 封禁 IP 地址
```bash
# 手动封禁某个 IP
sudo fail2ban-client set diary-family banip 192.168.1.100
```
### 高级配置
#### 使用 UFW 作为防火墙后端
如果使用 UFW 防火墙,修改配置:
```bash
# 编辑监狱配置
sudo nano /etc/fail2ban/jail.d/diary-family.conf
# 修改 banaction
banaction = ufw
# 重启服务
sudo systemctl restart fail2ban
```
#### 配置邮件通知
启用邮件通知功能:
```bash
# 编辑监狱配置
sudo nano /etc/fail2ban/jail.d/diary-family.conf
# 添加邮件配置
destemail = admin@example.com
sender = fail2ban@example.com
mta = sendmail
action = %(action_mwl)s
# 重启服务
sudo systemctl restart fail2ban
```
#### 调整封禁策略
编辑 `/etc/fail2ban/jail.d/diary-family.conf`
```ini
# 更严格的策略3次失败封禁24小时
maxretry = 3
bantime = 86400
findtime = 300
# 或者更宽松的策略10次失败封禁30分钟
maxretry = 10
bantime = 1800
findtime = 900
```
### 故障排除
#### 问题1Fail2ban 无法启动
```bash
# 检查配置文件语法
sudo fail2ban-client -t
# 查看详细错误信息
sudo journalctl -u fail2ban -f
# 检查日志文件权限
ls -la /var/log/syslog
ls -la /var/www/diary-family/logs/auth.log
```
#### 问题2无法检测到登录失败
```bash
# 检查日志格式是否匹配
sudo fail2ban-regex /var/log/syslog /etc/fail2ban/filter.d/diary-family.conf
# 手动检查日志内容
grep "Authentication failure" /var/log/syslog
grep "Authentication failure" /var/www/diary-family/logs/auth.log
# 检查 Django 是否正确记录日志
tail -f /var/www/diary-family/logs/auth.log
```
#### 问题3IP 未被封禁
```bash
# 检查 iptables 规则
sudo iptables -L -n | grep fail2ban
# 检查封禁状态
sudo fail2ban-client status diary-family
# 检查日志中是否有封禁动作
sudo grep "Ban" /var/log/fail2ban.log
```
#### 问题4syslog 无法写入
如果使用 syslog 出现权限问题,可以只使用文件日志:
```bash
# 编辑监狱配置,只监控 auth.log
sudo nano /etc/fail2ban/jail.d/diary-family.conf
# 修改 logpath
logpath = /var/www/diary-family/logs/auth.log
# 重启服务
sudo systemctl restart fail2ban
```
### 安全建议
1. **合理设置阈值**:根据实际需求调整 `maxretry``findtime`,避免误封正常用户
2. **配置白名单**:将办公网络、家庭网络等添加到 `ignoreip`
3. **定期检查日志**:定期查看 `/var/log/fail2ban.log` 了解封禁情况
4. **设置永久封禁**:对于频繁攻击的 IP可以手动永久封禁或设置很长的 `bantime`
5. **监控异常**:结合邮件通知,及时了解安全事件
### 与 Nginx 集成(可选)
如果使用 Nginx 作为反向代理,可以额外配置 Nginx 日志监控:
```bash
# 创建 Nginx 过滤器
sudo tee /etc/fail2ban/filter.d/nginx-diary-family.conf << 'EOF'
[Definition]
failregex = ^<HOST> .* "POST /login/ HTTP/.*" (401|403|500)
^<HOST> .* "POST /login/ HTTP/.*" 200 .* "Invalid login"
ignoreregex =
EOF
# 添加到监狱配置
sudo tee -a /etc/fail2ban/jail.d/diary-family.conf << 'EOF'
[nginx-diary-family]
enabled = true
filter = nginx-diary-family
logpath = /var/log/nginx/access.log
maxretry = 5
bantime = 3600
findtime = 600
EOF
# 重启服务
sudo systemctl restart fail2ban
```
## 注意事项
2026-01-04 19:21:52 +08:00
1. 定期备份数据库
2. 生产环境建议使用PostgreSQL或MySQL数据库
3. 定期清理过期数据
4. 保持依赖包更新
5. 定期运行邮件测试脚本,确保邮件功能正常
6. **Fail2ban 配置**:生产环境务必配置 Fail2ban 防止暴力破解
7. **白名单设置**:配置 `ignoreip` 避免误封自己的 IP
2026-01-04 19:21:52 +08:00
## 许可证
2026-01-04 19:21:52 +08:00
MIT License