django_apscheduler真实完整例子

整体步骤:

  1. 安装django-apscheduler

  2. 添加到INSTALLED_APPS

  3. 运行迁移,创建数据库表

  4. 创建任务函数

  5. 在apps.py中启动调度器,避免多实例重复运行

  6. 配置调度器,添加定时任务

  7. 运行服务器并测试

需要验证每个步骤是否正确,特别是调度器的启动位置,是否在Django应用加载时正确初始化,以及任务是否被正确调度。同时提醒用户注意可能的问题,比如时区设置,任务执行时间等。以下是使用 django_apscheduler 的完整示例,涵盖安装、配置、任务定义、调度及运行步骤:

1. 环境准备

安装包

bash

python 复制代码
pip install django-apscheduler

2. Django 项目配置

修改 settings.py

python

python 复制代码
INSTALLED_APPS = [
    # ...
    'django_apscheduler',  # 添加此应用
]

# 时区配置(可选,但建议明确)
TIME_ZONE = 'Asia/Shanghai'
USE_TZ = True
创建数据库表(迁移)

bash

python 复制代码
python manage.py migrate

3. 定义定时任务

创建任务函数 jobs.py

python

python 复制代码
# myapp/jobs.py
from django_apscheduler.jobstores import DjangoJobStore
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger
from django.conf import settings

def my_scheduled_job():
    """示例任务:每分钟打印日志"""
    print("[APScheduler] 定时任务执行成功!")


def start_scheduler():
    """启动调度器"""
    scheduler = BackgroundScheduler(timezone=settings.TIME_ZONE)
    scheduler.add_jobstore(DjangoJobStore(), "default")

    # 添加任务(每分钟执行一次)
    scheduler.add_job(
        my_scheduled_job,
        trigger=CronTrigger(second="0"),  # 每分钟的第0秒触发
        id="my_job",
        max_instances=1,
        replace_existing=True,
    )

    # 启动调度器
    try:
        scheduler.start()
    except KeyboardInterrupt:
        scheduler.shutdown()

4. 集成到 Django 应用

修改 apps.py(确保调度器只启动一次)

python

python 复制代码
# myapp/apps.py
from django.apps import AppConfig

class MyAppConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'myapp'

    def ready(self):
        """Django 启动时自动初始化调度器"""
        if not settings.DEBUG:  # 生产环境启动,或根据需求调整
            from .jobs import start_scheduler
            start_scheduler()
修改 __init__.py

python

python 复制代码
# myapp/__init__.py
default_app_config = 'myapp.apps.MyAppConfig'

5. 运行与验证

启动 Django 服务

bash

python 复制代码
python manage.py runserver
查看日志输出

plaintext

复制代码
[APScheduler] 定时任务执行成功!  # 每分钟输出一次

6. 高级功能(可选)

在 Django Admin 中管理任务
  • django_apscheduler 自动注册模型到 Admin,访问 /admin 可查看任务状态:
动态添加任务(示例)

python

python 复制代码
# 在代码中动态添加一次性任务
from apscheduler.triggers.date import DateTrigger
from datetime import datetime, timedelta

def add_one_time_job():
    scheduler = BackgroundScheduler()
    scheduler.add_job(
        my_scheduled_job,
        trigger=DateTrigger(run_date=datetime.now() + timedelta(minutes=5)),
        id="one_time_job",
    )

7. 处理多实例冲突

若部署多个 Django 实例,需通过数据库锁避免任务重复执行:

python

复制

复制代码
# 在 jobs.py 的 start_scheduler 中添加锁机制
from django_apscheduler.models import DjangoJobExecution

DjangoJobExecution.objects.select_for_update().filter(job_id="my_job").exists()

完整项目结构

复制代码
myproject/
├── myproject/
│   ├── settings.py
│   └── urls.py
└── myapp/
    ├── __init__.py
    ├── apps.py
    ├── jobs.py
    ├── models.py
    └── admin.py

8.注意事项

  1. 开发环境 :在 DEBUG=True 时可能因代码重载导致调度器多次启动,建议通过 if not settings.DEBUG 控制。

  2. 持久化 :任务状态存储在数据库表 django_apscheduler_djangojobdjango_apscheduler_djangojobexecution 中。

  3. 时区 :确保 TIME_ZONE 配置一致,避免任务时间偏移。

通过以上步骤,你可以在 Django 中快速实现轻量级定时任务调度!

9.多应用APP处理

在 Django 项目中,如果存在多个应用(Apps),使用 django_apscheduler 需要合理组织代码以避免任务冲突或重复执行。以下是详细的解决方案:

1. 核心原则
  • 避免多次启动调度器 :确保全局只有一个调度器实例(BackgroundScheduler),否则会引发线程冲突。

  • 集中管理任务注册 :推荐将所有任务的注册逻辑集中在一个位置(如某个 App 或中间件中),而非分散到多个 App 的 ready() 方法中。

  • 任务 ID 唯一性 :不同 App 中的任务需要唯一标识符(id 参数),避免覆盖或冲突。

2. 推荐方案:集中式调度器管理
步骤 1:创建一个专用 App(如 scheduler

bash

复制代码
python manage.py startapp scheduler
步骤 2:在 scheduler 中定义全局调度器

python

python 复制代码
# scheduler/jobs.py
from apscheduler.schedulers.background import BackgroundScheduler
from django_apscheduler.jobstores import DjangoJobStore
from django.conf import settings

# 全局调度器实例
scheduler = None

def init_scheduler():
    global scheduler
    if not scheduler:
        scheduler = BackgroundScheduler(timezone=settings.TIME_ZONE)
        scheduler.add_jobstore(DjangoJobStore(), "default")
    return scheduler
步骤 3:其他 App 定义任务(以 app1app2 为例)

python

python 复制代码
# app1/tasks.py
def app1_task():
    print("App1 定时任务执行")

# app2/tasks.py
def app2_task():
    print("App2 定时任务执行")
步骤 4:在 scheduler 中统一注册所有任务

python

python 复制代码
# scheduler/jobs.py(续)
from app1.tasks import app1_task
from app2.tasks import app2_task

def register_jobs():
    scheduler = init_scheduler()
    
    # 注册 app1 的任务(每天凌晨执行)
    scheduler.add_job(
        app1_task,
        trigger="cron", hour=0, minute=0,
        id="app1_daily_task",
        replace_existing=True  # 避免重复注册
    )
    
    # 注册 app2 的任务(每小时执行)
    scheduler.add_job(
        app2_task,
        trigger="interval", hours=1,
        id="app2_hourly_task",
        replace_existing=True
    )
    
    return scheduler
步骤 5:在 scheduler 的 AppConfig 中启动调度器

python

python 复制代码
# scheduler/apps.py
from django.apps import AppConfig
from django.conf import settings

class SchedulerConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'scheduler'

    def ready(self):
        if not settings.DEBUG:  # 生产环境启动
            from .jobs import init_scheduler, register_jobs
            scheduler = init_scheduler()
            register_jobs()
            try:
                scheduler.start()
            except KeyboardInterrupt:
                scheduler.shutdown()
步骤 6:配置 settings.py

python

python 复制代码
INSTALLED_APPS = [
    # ...
    'django_apscheduler',
    'app1',
    'app2',
    'scheduler',  # 确保最后加载,以便其他 App 的任务已定义
]
3. 替代方案:分散式任务注册(需谨慎)

如果希望每个 App 管理自己的任务,需确保调度器仅初始化一次:

在公共模块中定义调度器

python

python 复制代码
# core/scheduler.py
from apscheduler.schedulers.background import BackgroundScheduler
from django_apscheduler.jobstores import DjangoJobStore
from django.conf import settings

scheduler = BackgroundScheduler(timezone=settings.TIME_ZONE)
scheduler.add_jobstore(DjangoJobStore(), "default")

def get_scheduler():
    return scheduler

在每个 App 的 ready() 中注册任务

python

python 复制代码
# app1/apps.py
from django.apps import AppConfig
from core.scheduler import get_scheduler

class App1Config(AppConfig):
    def ready(self):
        scheduler = get_scheduler()
        if not scheduler.running:
            scheduler.start()
        
        # 注册任务
        scheduler.add_job(
            self.my_task,
            trigger="interval", minutes=30,
            id="app1_task",
            replace_existing=True
        )
    
    def my_task(self):
        print("App1 任务执行")

风险提示

  • 需确保 scheduler.start() 只调用一次。

  • 多个 App 的 ready() 加载顺序可能导致竞争条件。

4. 多实例部署的冲突处理

若项目部署多个实例(如多台服务器或多容器),需通过数据库锁避免重复执行:

python

python 复制代码
# scheduler/jobs.py(续)
from django_apscheduler.models import DjangoJobExecution

def register_jobs():
    scheduler = init_scheduler()
    
    # 注册任务时检查锁
    with transaction.atomic():
        job, created = DjangoJobExecution.objects.select_for_update().get_or_create(
            job_id="app1_daily_task",
            defaults={"status": "idle"}
        )
        if created:
            scheduler.add_job(...)
5. 项目结构示例
复制代码
myproject/
├── core/
│   └── scheduler.py          # 全局调度器定义(可选方案)
├── app1/
│   ├── tasks.py              # 定义 app1 的任务
│   ├── apps.py
├── app2/
│   ├── tasks.py              # 定义 app2 的任务
│   ├── apps.py
├── scheduler/                # 专用调度器 App
│   ├── jobs.py               # 注册所有任务
│   ├── apps.py
├── myproject/
│   ├── settings.py
│   └── urls.py

6. 注意事项

  1. 避免 DEBUG 模式重复启动 :在 settings.DEBUG=True 时,Django 可能会因代码重载多次初始化调度器,建议通过环境变量或 AppConfig 条件判断控制。

  2. 任务 ID 唯一性 :跨 App 的任务必须使用唯一 id,否则后注册的任务会覆盖先前的。

  3. 数据库清理 :定期清理 DjangoJobExecution 表,避免历史记录堆积:

    bash

    python 复制代码
    python manage.py delete_old_job_executions 7  # 删除7天前的记录
总结
  • 多 App 场景推荐集中式管理 :通过一个专用 App(如 scheduler)统一注册任务,确保调度器单例。

  • 动态任务需谨慎:若需动态添加任务(如通过 API),需保证线程安全和任务 ID 唯一性。

  • 生产环境高可用:多实例部署时结合数据库锁或外部协调服务(如 Redis 分布式锁)。

相关推荐
TlSfoward6 小时前
抓包代理链路下的 TLS 指纹变化分析 TLSFOWARD抓包工具
数据库·爬虫·网络协议·搜索引擎·php
数智化管理手记7 小时前
账龄分析手工统计易遗漏?自动账龄分析工具怎么搭建
大数据·网络·数据库·人工智能·数据挖掘
LabVIEW开发7 小时前
NI Package Manager安装LabVIEW时InternalServerError错误
网络·数据库·labview·labview知识·labview功能·labview程序
培之7 小时前
RTX 5090 安装 pytorch3d
人工智能·pytorch·python
SelectDB7 小时前
PostgreSQL 实时同步到 Apache Doris:一站式 CDC 解决方案
数据库
Metaphor6927 小时前
使用 Python 在 PowerPoint 中创建折线图和条形图
python·信息可视化·powerpoint·图表
Database_Cool_8 小时前
AI Agent 长期记忆怎么存?阿里云 PolarDB-X 对接 Mem0 记忆框架实践
数据库·阿里云
会编程的土豆8 小时前
数据库范式
数据库·oracle
L1624768 小时前
MySQL 全环境生产快速安装 + 完整配置手册(整合国产银河麒麟适配 + 主从补充版)
数据库·mysql
yio_yin8 小时前
Spring事务管理(数据一致性)
数据库·sql·spring