如何在Django中使用SQLite创建触发器实现30天无评论问题自动删除
实现方案
前置准备
首先确认你的模型满足以下基础条件,没有的话需要先补全字段并执行迁移:
Question模型存在DateTimeField类型的created_at字段,用于记录问题发布时间,建议设置auto_now_add=True自动填充创建时间Comment模型存在指向Question的外键字段,用于关联对应问题
示例模型参考:
from django.db import models class Question(models.Model): title = models.CharField(max_length=200) content = models.TextField() created_at = models.DateTimeField(auto_now_add=True) class Comment(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name='comments') content = models.TextField() created_at = models.DateTimeField(auto_now_add=True)
注意:SQLite 作为嵌入式数据库没有内置的定时调度能力,无法实现到点自动执行的逻辑,以下触发器会在每次对
question或comments表执行写入操作时,自动清理所有满足「发布满30天且无评论」的问题数据,如果你需要严格的到点自动清理,可以搭配系统级定时任务辅助。
步骤1:创建空迁移文件
Django的自定义SQL逻辑需要通过迁移文件同步到数据库,执行以下命令生成空迁移,将your_app_name替换为你的应用名:
python manage.py makemigrations your_app_name --empty
步骤2:在迁移文件中添加触发器逻辑
打开生成的迁移文件,替换内容如下,注意替换所有your_app_name为你的实际应用名,dependencies中的上一个迁移文件名也需要和你的项目匹配:
from django.db import migrations class Migration(migrations.Migration): dependencies = [ ('your_app_name', '0001_initial'), ] operations = [ # 新增问题后触发清理 migrations.RunSQL( """ CREATE TRIGGER IF NOT EXISTS clean_old_question_after_insert AFTER INSERT ON your_app_name_question BEGIN DELETE FROM your_app_name_question WHERE created_at <= DATETIME('now', '-30 days') AND id NOT IN (SELECT DISTINCT question_id FROM your_app_name_comment); END; """, reverse_sql="DROP TRIGGER IF EXISTS clean_old_question_after_insert;" ), # 新增评论后触发清理 migrations.RunSQL( """ CREATE TRIGGER IF NOT EXISTS clean_old_question_after_comment_insert AFTER INSERT ON your_app_name_comment BEGIN DELETE FROM your_app_name_question WHERE created_at <= DATETIME('now', '-30 days') AND id NOT IN (SELECT DISTINCT question_id FROM your_app_name_comment); END; """, reverse_sql="DROP TRIGGER IF EXISTS clean_old_question_after_comment_insert;" ) ]
步骤3:执行迁移生效
运行以下命令将触发器写入SQLite数据库:
python manage.py migrate
可选补充:定时全量清理
如果需要确保即使没有写入操作也能定期清理过期数据,可以自定义Django命令配合系统定时任务实现:
- 在应用目录下创建
management/commands/clean_old_questions.py文件,内容如下:
from django.core.management.base import BaseCommand from django.db import connection class Command(BaseCommand): help = "清理发布满30天无评论的问题" def handle(self, *args, **options): with connection.cursor() as cursor: cursor.execute(""" DELETE FROM your_app_name_question WHERE created_at <= DATETIME('now', '-30 days') AND id NOT IN (SELECT DISTINCT question_id FROM your_app_name_comment); """) self.stdout.write(self.style.SUCCESS(f"成功清理{cursor.rowcount}条过期无评论问题"))
- 在系统crontab中添加定时任务,示例为每天凌晨2点执行一次:
0 2 * * * /path/to/your/python/env/bin/python /path/to/your/project/manage.py clean_old_questions
内容的提问来源于stack exchange,提问作者Joeduciel
相关产品推荐
相关产品推荐

