RealtyCalendar plugin
This commit is contained in:
@@ -1,16 +1,14 @@
|
||||
from django.contrib import admin
|
||||
from django import forms
|
||||
from django.utils.functional import cached_property
|
||||
from .models import ScheduledTask
|
||||
from django.templatetags.static import static
|
||||
from scheduler.utils import get_project_functions
|
||||
|
||||
class CustomAdmin(admin.ModelAdmin):
|
||||
class Media:
|
||||
css = {"all": (static("scheduler/admin.css"),)}
|
||||
js = (static("scheduler/admin.js"),)
|
||||
|
||||
class ScheduledTaskForm(forms.ModelForm):
|
||||
"""
|
||||
Форма для модели ScheduledTask с кастомным полем для выбора дней недели.
|
||||
"""
|
||||
DAYS_OF_WEEK_CHOICES = [
|
||||
(0, "Воскресенье"),
|
||||
(1, "Понедельник"),
|
||||
@@ -25,7 +23,7 @@ class ScheduledTaskForm(forms.ModelForm):
|
||||
choices=DAYS_OF_WEEK_CHOICES,
|
||||
widget=forms.CheckboxSelectMultiple,
|
||||
label="Дни недели",
|
||||
required=False, # Опционально
|
||||
required=False,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
@@ -36,24 +34,32 @@ class ScheduledTaskForm(forms.ModelForm):
|
||||
"minutes",
|
||||
"hours",
|
||||
"months",
|
||||
"weekdays", # Используем только поле с галочками
|
||||
"weekdays",
|
||||
"active",
|
||||
]
|
||||
|
||||
def clean_weekdays(self):
|
||||
"""
|
||||
Преобразуем список выбранных дней в строку для хранения в базе.
|
||||
Преобразует список выбранных дней в строку для сохранения в базе.
|
||||
"""
|
||||
weekdays = self.cleaned_data.get("weekdays", [])
|
||||
return ",".join(map(str, weekdays))
|
||||
|
||||
|
||||
|
||||
@admin.register(ScheduledTask)
|
||||
class ScheduledTaskAdmin(admin.ModelAdmin):
|
||||
"""
|
||||
Кастомный класс для управления ScheduledTask в админке.
|
||||
"""
|
||||
form = ScheduledTaskForm
|
||||
list_display = ("task_name", "function_path", "minutes", "hours", "months", "weekdays", "active", "formatted_last_run")
|
||||
list_filter = ("active",)
|
||||
search_fields = ("task_name", "function_path")
|
||||
|
||||
def formatted_last_run(self, obj):
|
||||
"""
|
||||
Отформатированный вывод времени последнего запуска задачи.
|
||||
"""
|
||||
return obj.last_run.strftime("%Y-%m-%d %H:%M:%S") if obj.last_run else "Никогда"
|
||||
formatted_last_run.short_description = "Последний запуск"
|
||||
|
||||
formatted_last_run.short_description = "Последний запуск"
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
from django.apps import AppConfig
|
||||
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||
|
||||
scheduler_instance = AsyncIOScheduler()
|
||||
|
||||
class SchedulerConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'scheduler'
|
||||
verbose_name="Планировщик заданий"
|
||||
verbose_name = 'Планировщик задач'
|
||||
def ready(self):
|
||||
"""
|
||||
Метод ready вызывается при старте приложения.
|
||||
Здесь не нужно запускать scheduler_instance.start(), чтобы избежать ошибок.
|
||||
"""
|
||||
pass
|
||||
|
||||
39
scheduler/management/commands/start_scheduler.py
Normal file
39
scheduler/management/commands/start_scheduler.py
Normal file
@@ -0,0 +1,39 @@
|
||||
import asyncio
|
||||
from django.core.management.base import BaseCommand
|
||||
from scheduler.apps import scheduler_instance
|
||||
from scheduler.tasks import load_tasks_to_scheduler
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Запуск планировщика задач"
|
||||
|
||||
def handle(self, *args, **kwargs):
|
||||
"""
|
||||
Создаёт новый event loop, запускает планировщик и загружает задачи.
|
||||
"""
|
||||
try:
|
||||
print("Проверка состояния перед запуском:")
|
||||
print(f"Scheduler instance: {scheduler_instance}")
|
||||
|
||||
# Создаём новый event loop
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
|
||||
# Устанавливаем event loop в планировщик
|
||||
scheduler_instance.configure(event_loop=loop)
|
||||
|
||||
# Запускаем планировщик
|
||||
scheduler_instance.start()
|
||||
|
||||
# Загружаем задачи
|
||||
load_tasks_to_scheduler(scheduler_instance)
|
||||
|
||||
self.stdout.write(self.style.SUCCESS("Планировщик успешно запущен."))
|
||||
|
||||
# Удерживаем цикл событий
|
||||
loop.run_forever()
|
||||
except KeyboardInterrupt:
|
||||
self.stdout.write(self.style.WARNING("Остановка планировщика."))
|
||||
finally:
|
||||
# Завершаем работу планировщика
|
||||
scheduler_instance.shutdown(wait=False)
|
||||
@@ -1,30 +0,0 @@
|
||||
# Generated by Django 5.1.4 on 2024-12-10 08:38
|
||||
|
||||
import scheduler.models
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ScheduledTask',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('task_name', models.CharField(max_length=255, verbose_name='Название задачи')),
|
||||
('function_path', models.CharField(choices=scheduler.models.get_available_functions, max_length=500, verbose_name='Путь к функции (модуль.функция)')),
|
||||
('minutes', models.CharField(default='*', max_length=255, verbose_name='Минуты')),
|
||||
('hours', models.CharField(default='*', max_length=255, verbose_name='Часы')),
|
||||
('days', models.CharField(default='*', max_length=255, verbose_name='Дни')),
|
||||
('months', models.CharField(default='*', max_length=255, verbose_name='Месяцы')),
|
||||
('weekdays', models.JSONField(default=list, verbose_name='Дни недели')),
|
||||
('active', models.BooleanField(default=True, verbose_name='Активно')),
|
||||
('last_run', models.DateTimeField(blank=True, null=True, verbose_name='Последний запуск')),
|
||||
],
|
||||
),
|
||||
]
|
||||
17
scheduler/reload_tasks.py
Normal file
17
scheduler/reload_tasks.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from scheduler.tasks import load_tasks_to_scheduler
|
||||
from scheduler.apps import scheduler_instance
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Перезагрузка задач в планировщике"
|
||||
|
||||
def handle(self, *args, **kwargs):
|
||||
try:
|
||||
# Удаляем все существующие задачи
|
||||
scheduler_instance.remove_all_jobs()
|
||||
|
||||
# Загружаем задачи заново
|
||||
load_tasks_to_scheduler(scheduler_instance)
|
||||
self.stdout.write(self.style.SUCCESS("Задачи успешно перезагружены."))
|
||||
except Exception as e:
|
||||
self.stdout.write(self.style.ERROR(f"Ошибка перезагрузки задач: {e}"))
|
||||
@@ -5,7 +5,6 @@ from scheduler.models import ScheduledTask
|
||||
import importlib
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
|
||||
|
||||
def format_weekdays(weekdays):
|
||||
"""Преобразует список дней недели в строку."""
|
||||
if isinstance(weekdays, list):
|
||||
@@ -43,7 +42,10 @@ def setup_scheduler():
|
||||
print("Планировщик запущен.")
|
||||
return scheduler
|
||||
|
||||
def load_tasks_to_scheduler(scheduler: BaseScheduler):
|
||||
def load_tasks_to_scheduler(scheduler):
|
||||
"""
|
||||
Загружает активные задачи в планировщик.
|
||||
"""
|
||||
tasks = ScheduledTask.objects.filter(active=True)
|
||||
for task in tasks:
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user