如何在一天后自动更新Django模型中的is_new字段为False?
实现Django文章发布一天后自动标记为非新状态的方案
方案一:用Celery + Celery Beat定时修改数据库字段
适合需要持久化is_new字段状态的场景,步骤如下:
- 安装依赖
pip install celery redis
(这里以Redis作为消息中间件,也可替换为RabbitMQ等其他选项)
- 配置Celery
在项目根目录创建celery.py:
import os from celery import Celery os.environ.setdefault('DJANGO_SETTINGS_MODULE', '你的项目名.settings') app = Celery('你的项目名') app.config_from_object('django.conf:settings', namespace='CELERY') app.autodiscover_tasks()
在项目根目录的__init__.py中添加:
from .celery import app as celery_app __all__ = ('celery_app',)
- 创建定时任务
在你的app目录下创建tasks.py:
from celery import shared_task from django.utils import timezone from .models import post @shared_task def update_is_new_status(): one_day_ago = timezone.now() - timezone.timedelta(days=1) # 批量更新符合条件的文章 post.objects.filter(created_at__lte=one_day_ago, is_new=True).update(is_new=False)
- 配置定时规则
在项目settings.py中添加:
from celery.schedules import crontab CELERY_BEAT_SCHEDULE = { 'daily-update-is-new': { 'task': '你的app名称.tasks.update_is_new_status', # 每天执行一次,也可以用crontab指定具体时间,比如凌晨2点: # 'schedule': crontab(hour=2, minute=0), 'schedule': timezone.timedelta(hours=24), }, } # 配置消息中间件和结果存储 CELERY_BROKER_URL = 'redis://localhost:6379/0' CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
- 启动服务
# 启动Celery Worker处理任务 celery -A 你的项目名 worker --loglevel=info # 启动Celery Beat调度定时任务 celery -A 你的项目名 beat --loglevel=info
方案二:动态计算is_new状态(无需维护数据库字段)
如果不需要把is_new存在数据库里,这种方式更高效,避免定时任务的维护成本:
方法1:给模型添加属性
修改post模型,将is_new改为动态计算的属性:
from django.utils import timezone class post(models.Model): title = models.CharField(max_length=250) body = RichTextField(blank=True, null=True) created_at = models.DateTimeField(auto_now_add=True) # 移除原来的is_new字段 # is_new = models.BooleanField(default=True) @property def is_new(self): # 判断发布时间是否在一天以内 return timezone.now() - self.created_at <= timezone.timedelta(days=1)
之后在视图或模板中直接调用article.is_new就能获取实时状态。
方法2:自定义模型管理器(批量查询用)
如果需要批量筛选新文章,可自定义管理器:
from django.db import models from django.utils import timezone class PostManager(models.Manager): def new_posts(self): one_day_ago = timezone.now() - timezone.timedelta(days=1) return self.filter(created_at__gte=one_day_ago) class post(models.Model): title = models.CharField(max_length=250) body = RichTextField(blank=True, null=True) created_at = models.DateTimeField(auto_now_add=True) objects = PostManager()
使用时通过post.objects.new_posts()就能快速获取发布一天内的文章。
内容的提问来源于stack exchange,提问作者USER2022
相关产品推荐
相关产品推荐

