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

Django中如何让用户全权限布尔字段6个月后自动重置为默认值

解决Django用户全权限6个月自动过期的问题

嘿,作为Django新手碰到这个权限自动过期的需求太正常啦~ 你现在的代码只是把has_full_access设为True,但没记录权限授予的时间,所以没法追踪过期时间。我给你分享几个实用的解决方案,一步步来:

第一步:先给模型添加权限授予时间字段

首先得在你的CustomUser模型里加一个字段,记录用户获得全权限的时间,这样才能计算6个月后是否过期:

# models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.utils import timezone

class CustomUser(AbstractUser):
    full_name = models.CharField(blank=True, max_length=255)
    has_full_access = models.BooleanField(default=False)
    # 新增字段:记录权限授予时间
    full_access_granted_at = models.DateTimeField(null=True, blank=True)
    # some other stuff

然后别忘了执行迁移命令:

python manage.py makemigrations
python manage.py migrate

接下来修改你的视图,设置has_full_access=True的同时,把当前时间存入这个新字段:

# views.py
from django.utils import timezone

def data_gathered_done(request):
    current_user = CustomUser.objects.get(id=request.user.id)
    current_user.has_full_access = True
    # 记录权限授予时间
    current_user.full_access_granted_at = timezone.now()
    current_user.save()
    # some other stuff

现在有了时间记录,就可以实现自动过期了,下面是两种主流方案:


方案一:用定时任务后台自动处理(推荐给中大型网站)

这个方案用Celery+Beat来定期检查并过期权限,后台自动运行,不影响用户体验。

步骤:

  1. 安装依赖:先装Celery和消息中间件(比如Redis,也可以用RabbitMQ)
pip install celery redis
  1. 配置Celery:在你的Django项目根目录创建celery.py:
# celery.py
import os
from celery import Celery

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'your_project.settings')

app = Celery('your_project')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()

然后在项目的__init__.py里添加:

# __init__.py
from .celery import app as celery_app

__all__ = ('celery_app',)
  1. 创建定时任务:在你的app里创建tasks.py:
# tasks.py
from celery import shared_task
from django.utils import timezone
from datetime import timedelta
from .models import CustomUser

@shared_task
def expire_full_access_permissions():
    # 计算6个月前的时间(按180天估算,也可以用 relativedelta 更精确计算月数)
    six_months_ago = timezone.now() - timedelta(days=180)
    # 找到所有权限已过期的用户
    expired_users = CustomUser.objects.filter(
        has_full_access=True,
        full_access_granted_at__lt=six_months_ago
    )
    # 批量更新为False,比逐个save()效率高
    expired_users.update(has_full_access=False)
  1. 配置Celery Beat定期执行:在settings.py里添加Beat的配置:
# settings.py
from datetime import timedelta

CELERY_BEAT_SCHEDULE = {
    'expire-full-access-every-day': {
        'task': 'your_app.tasks.expire_full_access_permissions',
        # 每天执行一次,也可以设成更频繁的比如每小时
        'schedule': timedelta(days=1),
    },
}
  1. 启动服务:
# 启动Redis(如果用Redis作为消息中间件的话)
redis-server

# 启动Celery worker
celery -A your_project worker --loglevel=info

# 启动Celery Beat(负责触发定时任务)
celery -A your_project beat --loglevel=info

方案二:用户访问时即时检查(适合小型网站,无需额外服务)

如果你的网站流量不大,不想折腾Celery,可以在用户每次访问需要权限的页面时,检查权限是否过期,即时更新。

方法1:用自定义中间件

创建一个中间件,每次请求都检查当前用户的权限:

# middleware.py
from django.utils import timezone
from datetime import timedelta
from .models import CustomUser

class CheckFullAccessExpiryMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        if request.user.is_authenticated:
            user = request.user
            if user.has_full_access and user.full_access_granted_at:
                six_months_ago = timezone.now() - timedelta(days=180)
                if user.full_access_granted_at < six_months_ago:
                    user.has_full_access = False
                    user.save()
        response = self.get_response(request)
        return response

然后在settings.py的MIDDLEWARE里添加这个中间件:

# settings.py
MIDDLEWARE = [
    # ...其他中间件
    'your_app.middleware.CheckFullAccessExpiryMiddleware',
]

方法2:用装饰器

如果只需要在特定视图检查,可以写一个装饰器:

# decorators.py
from django.utils import timezone
from datetime import timedelta
from .models import CustomUser

def check_full_access_expiry(view_func):
    def wrapper(request, *args, **kwargs):
        if request.user.is_authenticated:
            user = request.user
            if user.has_full_access and user.full_access_granted_at:
                six_months_ago = timezone.now() - timedelta(days=180)
                if user.full_access_granted_at < six_months_ago:
                    user.has_full_access = False
                    user.save()
        return view_func(request, *args, **kwargs)
    return wrapper

然后在需要的视图上使用:

# views.py
from .decorators import check_full_access_expiry

@check_full_access_expiry
def some_protected_view(request):
    # 你的视图逻辑
    pass

注意事项

  • 时区问题:一定要用django.utils.timezone.now()而不是Python原生的datetime.datetime.now(),确保和Django的时区设置一致,避免过期时间计算错误。
  • 精确计算月数:如果需要严格按6个月(比如2月到8月,不管天数)计算,可以用dateutil.relativedelta,需要先安装python-dateutil,然后替换timedelta(days=180)为relativedelta(months=6)。
  • 测试技巧:测试的时候可以把过期时间改成timedelta(minutes=1),这样1分钟后就能看到过期效果,方便调试。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:25:13