You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Django FSM将1天未活跃的用户设为非活跃状态

使用Django FSM自动将1天未活跃用户标记为非活跃状态

原代码存在的问题

  • 条件函数state_inactive违反Django FSM设计规则:条件函数仅需返回布尔值判断转换是否允许,不应直接修改字段或调用save()
  • date字段为创建时间,无法跟踪用户最后活跃时间,不符合"1天未活跃"的需求逻辑
  • 缺少批量触发状态转换的执行逻辑,无法自动处理所有符合条件的用户

修正后的完整实现

1. 修正模型定义

替换原模型,新增last_active字段跟踪用户最后活跃时间,规范FSM状态转换逻辑:

from django.db import models
from django_fsm import FSMField, transition
import datetime

class UserValidity(models.Model):
    STATE_CHOICES = (
        ('active', '活跃'),
        ('inactive', '非活跃'),
    )
    # 开启protected避免直接修改state字段,强制通过FSM转换
    state = FSMField(default="active", choices=STATE_CHOICES, protected=True)
    name = models.CharField(max_length=10)
    # 记录用户最后活跃时间,创建时自动赋值,用户活跃时更新
    last_active = models.DateTimeField(auto_now_add=True)

    # 条件函数:判断是否超过1天未活跃
    def is_eligible_for_inactive(self):
        one_day_ago = datetime.datetime.now() - datetime.timedelta(days=1)
        return self.last_active < one_day_ago

    @transition(field=state, source="active", target="inactive", conditions=[is_eligible_for_inactive])
    def mark_as_inactive(self):
        # 可在此添加状态转换后的额外逻辑(如发送通知、记录日志)
        print(f"用户 {self.name} 已切换为非活跃状态")

2. 批量处理未活跃用户

方式一:Django自定义命令(适合测试或手动触发)

在app目录下创建management/commands/mark_inactive_users.py:

from django.core.management.base import BaseCommand
from your_app.models import UserValidity

class Command(BaseCommand):
    help = '批量将1天未活跃的活跃用户标记为非活跃'

    def handle(self, *args, **options):
        processed_count = 0
        # 筛选所有活跃用户,逐一尝试状态转换
        for user in UserValidity.objects.filter(state='active'):
            # mark_as_inactive()仅在满足条件时执行转换并返回True
            if user.mark_as_inactive():
                processed_count += 1
        self.stdout.write(self.style.SUCCESS(f"完成处理,共标记 {processed_count} 个用户"))

执行命令:

python manage.py mark_inactive_users

方式二:Celery定时任务(生产环境自动执行)

创建Celery任务实现每日自动处理:

from celery import shared_task
from your_app.models import UserValidity

@shared_task
def auto_mark_inactive_users():
    processed_count = 0
    for user in UserValidity.objects.filter(state='active'):
        if user.mark_as_inactive():
            processed_count += 1
    return f"每日非活跃用户标记完成,共处理 {processed_count} 个用户"

在Celery配置中添加定时任务(例如每日凌晨执行):

from celery.schedules import crontab

CELERY_BEAT_SCHEDULE = {
    'daily-mark-inactive-users': {
        'task': 'your_app.tasks.auto_mark_inactive_users',
        'schedule': crontab(hour=0, minute=0),
    },
}

3. 更新用户活跃时间

当用户产生活跃行为(如登录、操作)时,更新last_active字段:

# 示例:用户登录时更新活跃时间
user = UserValidity.objects.get(name="test_user")
user.last_active = datetime.datetime.now()
user.save()

关键注意事项

  • 始终通过FSM的转换方法修改状态,避免直接赋值state字段,保证状态转换的合法性
  • 使用DateTimeField而非DateField,可以更精确地处理跨天的未活跃判断
  • 批量处理时不要直接用update()修改state,必须逐个调用转换方法,确保触发FSM的钩子逻辑

内容的提问来源于stack exchange,提问作者TMD

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 14:16:46