This commit is contained in:
Iliyan Angelov
2025-09-19 11:58:53 +03:00
parent 306b20e24a
commit 6b247e5b9f
11423 changed files with 1500615 additions and 778 deletions

View File

@@ -0,0 +1,29 @@
"""Database-backed Periodic Tasks."""
# :copyright: (c) 2016, Ask Solem.
# All rights reserved.
# :license: BSD (3 Clause), see LICENSE for more details.
import re
from collections import namedtuple
__version__ = '2.8.1'
__author__ = 'Asif Saif Uddin, Ask Solem'
__contact__ = 'auvipy@gmail.com, ask@celeryproject.org'
__homepage__ = 'https://github.com/celery/django-celery-beat'
__docformat__ = 'restructuredtext'
# -eof meta-
version_info_t = namedtuple('version_info_t', (
'major', 'minor', 'micro', 'releaselevel', 'serial',
))
# bumpversion can only search for {current_version}
# so we have to parse the version here.
_temp = re.match(
r'(\d+)\.(\d+).(\d+)(.+)?', __version__).groups()
VERSION = version_info = version_info_t(
int(_temp[0]), int(_temp[1]), int(_temp[2]), _temp[3] or '', '')
del _temp
del re
__all__ = []

View File

@@ -0,0 +1,326 @@
"""Periodic Task Admin interface."""
from celery import current_app
from celery.utils import cached_property
from django import forms
from django.conf import settings
from django.contrib import admin, messages
from django.db.models import Case, Value, When
from django.forms.widgets import Select
from django.template.defaultfilters import pluralize
from django.utils.translation import gettext_lazy as _
from django.utils.translation import ngettext_lazy
from kombu.utils.json import loads
from .models import (ClockedSchedule, CrontabSchedule, IntervalSchedule,
PeriodicTask, PeriodicTasks, SolarSchedule)
from .utils import is_database_scheduler
class TaskSelectWidget(Select):
"""Widget that lets you choose between task names."""
celery_app = current_app
_choices = None
def tasks_as_choices(self):
_ = self._modules
tasks = sorted(name for name in self.celery_app.tasks
if not name.startswith('celery.'))
return (('', ''), ) + tuple(zip(tasks, tasks))
@property
def choices(self):
if self._choices is None:
self._choices = self.tasks_as_choices()
return self._choices
@choices.setter
def choices(self, _):
# ChoiceField.__init__ sets ``self.choices = choices``
# which would override ours.
pass
@cached_property
def _modules(self):
self.celery_app.loader.import_default_modules()
class TaskChoiceField(forms.ChoiceField):
"""Field that lets you choose between task names."""
widget = TaskSelectWidget
def valid_value(self, value):
return True
class PeriodicTaskForm(forms.ModelForm):
"""Form that lets you create and modify periodic tasks."""
regtask = TaskChoiceField(
label=_('Task (registered)'),
required=False,
)
task = forms.CharField(
label=_('Task (custom)'),
required=False,
max_length=200,
)
class Meta:
"""Form metadata."""
model = PeriodicTask
exclude = ()
def clean(self):
data = super().clean()
regtask = data.get('regtask')
if regtask:
data['task'] = regtask
if not data['task']:
exc = forms.ValidationError(_('Need name of task'))
self._errors['task'] = self.error_class(exc.messages)
raise exc
if data.get('expire_seconds') is not None and data.get('expires'):
raise forms.ValidationError(
_('Only one can be set, in expires and expire_seconds')
)
return data
def _clean_json(self, field):
value = self.cleaned_data[field]
try:
loads(value)
except ValueError as exc:
raise forms.ValidationError(
_('Unable to parse JSON: %s') % exc,
)
return value
def clean_args(self):
return self._clean_json('args')
def clean_kwargs(self):
return self._clean_json('kwargs')
@admin.register(PeriodicTask)
class PeriodicTaskAdmin(admin.ModelAdmin):
"""Admin-interface for periodic tasks."""
form = PeriodicTaskForm
model = PeriodicTask
celery_app = current_app
date_hierarchy = 'start_time'
list_display = ('name', 'enabled', 'scheduler', 'interval', 'start_time',
'last_run_at', 'one_off')
list_filter = ['enabled', 'one_off', 'task', 'start_time', 'last_run_at']
actions = ('enable_tasks', 'disable_tasks', 'toggle_tasks', 'run_tasks')
search_fields = ('name', 'task',)
fieldsets = (
(None, {
'fields': ('name', 'regtask', 'task', 'enabled', 'description',),
'classes': ('extrapretty', 'wide'),
}),
(_('Schedule'), {
'fields': ('interval', 'crontab', 'crontab_translation', 'solar',
'clocked', 'start_time', 'last_run_at', 'one_off'),
'classes': ('extrapretty', 'wide'),
}),
(_('Arguments'), {
'fields': ('args', 'kwargs'),
'classes': ('extrapretty', 'wide', 'collapse', 'in'),
}),
(_('Execution Options'), {
'fields': ('expires', 'expire_seconds', 'queue', 'exchange',
'routing_key', 'priority', 'headers'),
'classes': ('extrapretty', 'wide', 'collapse', 'in'),
}),
)
readonly_fields = (
'last_run_at', 'crontab_translation',
)
def crontab_translation(self, obj):
return obj.crontab.human_readable
change_form_template = 'admin/djcelery/change_periodictask_form.html'
def changeform_view(self, request, object_id=None, form_url='',
extra_context=None):
extra_context = extra_context or {}
crontabs = CrontabSchedule.objects.all()
crontab_dict = {}
for crontab in crontabs:
crontab_dict[crontab.id] = crontab.human_readable
extra_context['readable_crontabs'] = crontab_dict
return super().changeform_view(request, object_id,
extra_context=extra_context)
def changelist_view(self, request, extra_context=None):
extra_context = extra_context or {}
scheduler = getattr(settings, 'CELERY_BEAT_SCHEDULER', None)
extra_context['wrong_scheduler'] = not is_database_scheduler(scheduler)
return super().changelist_view(
request, extra_context)
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.select_related('interval', 'crontab', 'solar', 'clocked')
@admin.action(
description=_('Enable selected tasks')
)
def enable_tasks(self, request, queryset):
rows_updated = queryset.update(enabled=True)
PeriodicTasks.update_changed()
self.message_user(
request,
ngettext_lazy(
'{0} task was successfully enabled',
'{0} tasks were successfully enabled',
rows_updated
).format(rows_updated)
)
@admin.action(
description=_('Disable selected tasks')
)
def disable_tasks(self, request, queryset):
rows_updated = queryset.update(enabled=False, last_run_at=None)
PeriodicTasks.update_changed()
self.message_user(
request,
ngettext_lazy(
'{0} task was successfully disabled',
'{0} tasks were successfully disabled',
rows_updated
).format(rows_updated)
)
def _toggle_tasks_activity(self, queryset):
return queryset.update(enabled=Case(
When(enabled=True, then=Value(False)),
default=Value(True),
))
@admin.action(
description=_('Toggle activity of selected tasks')
)
def toggle_tasks(self, request, queryset):
rows_updated = self._toggle_tasks_activity(queryset)
PeriodicTasks.update_changed()
self.message_user(
request,
ngettext_lazy(
'{0} task was successfully toggled',
'{0} tasks were successfully toggled',
rows_updated
).format(rows_updated)
)
@admin.action(
description=_('Run selected tasks')
)
def run_tasks(self, request, queryset):
self.celery_app.loader.import_default_modules()
tasks = [(self.celery_app.tasks.get(task.task),
loads(task.args),
loads(task.kwargs),
task.queue,
task.name)
for task in queryset]
if any(t[0] is None for t in tasks):
for i, t in enumerate(tasks):
if t[0] is None:
break
# variable "i" will be set because list "tasks" is not empty
not_found_task_name = queryset[i].task
self.message_user(
request,
_(f'task "{not_found_task_name}" not found'),
level=messages.ERROR,
)
return
task_ids = [
task.apply_async(
args=args,
kwargs=kwargs,
queue=queue,
headers={'periodic_task_name': periodic_task_name}
)
if queue and len(queue)
else task.apply_async(
args=args,
kwargs=kwargs,
headers={'periodic_task_name': periodic_task_name}
)
for task, args, kwargs, queue, periodic_task_name in tasks
]
tasks_run = len(task_ids)
self.message_user(
request,
_('{0} task{1} {2} successfully run').format(
tasks_run,
pluralize(tasks_run),
pluralize(tasks_run, _('was,were')),
),
)
class PeriodicTaskInline(admin.TabularInline):
model = PeriodicTask
fields = ('name', 'task', 'args', 'kwargs')
readonly_fields = fields
can_delete = False
extra = 0
show_change_link = True
verbose_name = "Periodic Tasks Using This Schedule"
verbose_name_plural = verbose_name
def has_add_permission(self, request, obj):
return False
class ScheduleAdmin(admin.ModelAdmin):
inlines = [PeriodicTaskInline]
@admin.register(ClockedSchedule)
class ClockedScheduleAdmin(ScheduleAdmin):
"""Admin-interface for clocked schedules."""
fields = (
'clocked_time',
)
list_display = (
'clocked_time',
)
@admin.register(CrontabSchedule)
class CrontabScheduleAdmin(ScheduleAdmin):
"""Admin class for CrontabSchedule."""
list_display = ('__str__', 'human_readable')
fields = ('human_readable', 'minute', 'hour', 'day_of_month',
'month_of_year', 'day_of_week', 'timezone')
readonly_fields = ('human_readable', )
@admin.register(SolarSchedule)
class SolarScheduleAdmin(ScheduleAdmin):
"""Admin class for SolarSchedule."""
pass
@admin.register(IntervalSchedule)
class IntervalScheduleAdmin(ScheduleAdmin):
"""Admin class for IntervalSchedule."""
pass

View File

@@ -0,0 +1,18 @@
"""Django Application configuration."""
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
__all__ = ['BeatConfig']
class BeatConfig(AppConfig):
"""Default configuration for django_celery_beat app."""
name = 'django_celery_beat'
label = 'django_celery_beat'
verbose_name = _('Periodic Tasks')
default_auto_field = 'django.db.models.AutoField'
def ready(self):
from .signals import signals_connect
signals_connect()

View File

@@ -0,0 +1,42 @@
"""Clocked schedule Implementation."""
from celery import schedules
from celery.utils.time import maybe_make_aware
from .utils import NEVER_CHECK_TIMEOUT
class clocked(schedules.BaseSchedule):
"""clocked schedule.
Depends on PeriodicTask one_off=True
"""
def __init__(self, clocked_time, nowfun=None, app=None):
"""Initialize clocked."""
self.clocked_time = maybe_make_aware(clocked_time)
super().__init__(nowfun=nowfun, app=app)
def remaining_estimate(self, last_run_at):
return self.clocked_time - self.now()
def is_due(self, last_run_at):
rem_delta = self.remaining_estimate(None)
remaining_s = max(rem_delta.total_seconds(), 0)
if remaining_s == 0:
return schedules.schedstate(is_due=True, next=NEVER_CHECK_TIMEOUT)
return schedules.schedstate(is_due=False, next=remaining_s)
def __repr__(self):
return f'<clocked: {self.clocked_time}>'
def __eq__(self, other):
if isinstance(other, clocked):
return self.clocked_time == other.clocked_time
return False
def __ne__(self, other):
return not self.__eq__(other)
def __reduce__(self):
return self.__class__, (self.clocked_time, self.nowfun)

View File

@@ -0,0 +1,554 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-12-22 18:56+0000\n"
"PO-Revision-Date: 2022-08-28 03:29+0200\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 3.1.1\n"
#: django_celery_beat/admin.py:60
msgid "Task (registered)"
msgstr "Aufgabe (registriert)"
#: django_celery_beat/admin.py:64
msgid "Task (custom)"
msgstr "Aufgabe (benutzerdefiniert)"
#: django_celery_beat/admin.py:81
msgid "Need name of task"
msgstr "Name der Aufgabe benötigt"
#: django_celery_beat/admin.py:87 django_celery_beat/models.py:605
msgid "Only one can be set, in expires and expire_seconds"
msgstr ""
"Es kann nur eine festgelegt werden, \"Ablaufdatum\" oder \"Ablauf-Timedelta "
"in Sekunden\""
#: django_celery_beat/admin.py:97
#, python-format
msgid "Unable to parse JSON: %s"
msgstr "Ausserstande JSON zu parsen: %s"
#: django_celery_beat/admin.py:125
msgid "Schedule"
msgstr "Zeitplan"
#: django_celery_beat/admin.py:130
msgid "Arguments"
msgstr "Argumente"
#: django_celery_beat/admin.py:134
msgid "Execution Options"
msgstr "Ausführungsoptionen"
#: django_celery_beat/admin.py:177
#, python-brace-format
msgid "{0} task{1} {2} successfully {3}"
msgstr "{0} Aufgabe{1} {2} erfolgreich {3}"
#: django_celery_beat/admin.py:180 django_celery_beat/admin.py:247
msgid "was,were"
msgstr "war,waren"
#: django_celery_beat/admin.py:189
msgid "Enable selected tasks"
msgstr "Ausgewählte Aufgaben aktivieren"
#: django_celery_beat/admin.py:195
msgid "Disable selected tasks"
msgstr "Ausgewählte Aufgaben deaktivieren"
#: django_celery_beat/admin.py:207
msgid "Toggle activity of selected tasks"
msgstr "Aktivität ausgewählter Aufgaben ein-/ausschalten"
#: django_celery_beat/admin.py:228
#, fuzzy, python-brace-format
#| msgid "task \"{0}\" not found"
msgid "task \"{not_found_task_name}\" not found"
msgstr "Aufgabe \"{0}\" nicht gefunden"
#: django_celery_beat/admin.py:244
#, python-brace-format
msgid "{0} task{1} {2} successfully run"
msgstr "{0} Aufgabe{1} {2} erfolgreich ausgeführt"
#: django_celery_beat/admin.py:250
msgid "Run selected tasks"
msgstr "Ausgewählte Aufgaben ausführen"
#: django_celery_beat/apps.py:13
msgid "Periodic Tasks"
msgstr "Periodische Aufgaben"
#: django_celery_beat/models.py:30
msgid "Days"
msgstr "Tage"
#: django_celery_beat/models.py:31
msgid "Hours"
msgstr "Stunden"
#: django_celery_beat/models.py:32
msgid "Minutes"
msgstr "Minuten"
#: django_celery_beat/models.py:33
msgid "Seconds"
msgstr "Sekunden"
#: django_celery_beat/models.py:34
msgid "Microseconds"
msgstr "Mikrosekunden"
#: django_celery_beat/models.py:38
msgid "Day"
msgstr "Tag"
#: django_celery_beat/models.py:39
msgid "Hour"
msgstr "Stunde"
#: django_celery_beat/models.py:40
msgid "Minute"
msgstr "Minute"
#: django_celery_beat/models.py:41
msgid "Second"
msgstr "Sekunde"
#: django_celery_beat/models.py:42
msgid "Microsecond"
msgstr "Mikrosekunde"
#: django_celery_beat/models.py:46
msgid "Astronomical dawn"
msgstr "Astronomische Morgendämmerung"
#: django_celery_beat/models.py:47
msgid "Civil dawn"
msgstr "Zivile Morgendämmerung"
#: django_celery_beat/models.py:48
msgid "Nautical dawn"
msgstr "Nautische Morgendämmerung"
#: django_celery_beat/models.py:49
msgid "Astronomical dusk"
msgstr "Astronomische Dämmerung"
#: django_celery_beat/models.py:50
msgid "Civil dusk"
msgstr "Zivile Dämmerung"
#: django_celery_beat/models.py:51
msgid "Nautical dusk"
msgstr "Nautische Dämmerung"
#: django_celery_beat/models.py:52
msgid "Solar noon"
msgstr "Sonnenmittag"
#: django_celery_beat/models.py:53
msgid "Sunrise"
msgstr "Sonnenaufgang"
#: django_celery_beat/models.py:54
msgid "Sunset"
msgstr "Sonnenuntergang"
#: django_celery_beat/models.py:88
msgid "Solar Event"
msgstr "Sonnenereigniss"
#: django_celery_beat/models.py:89
msgid "The type of solar event when the job should run"
msgstr "Die Art des Solarereignisses, wenn die Aufgabe ausgeführt werden soll"
#: django_celery_beat/models.py:93
msgid "Latitude"
msgstr "Breitengrad"
#: django_celery_beat/models.py:94
msgid "Run the task when the event happens at this latitude"
msgstr ""
"Führen Sie diese Aufgabe aus, wenn das Ereignis in diesem Breitengrad "
"auftritt"
#: django_celery_beat/models.py:99
msgid "Longitude"
msgstr "Längengrad"
#: django_celery_beat/models.py:100
msgid "Run the task when the event happens at this longitude"
msgstr ""
"Führen Sie diese Aufgabe aus, wenn das Ereignis in diesem Längengrad auftritt"
#: django_celery_beat/models.py:107
msgid "solar event"
msgstr "Sonnenereigniss"
#: django_celery_beat/models.py:108
msgid "solar events"
msgstr "Sonnenereignisse"
#: django_celery_beat/models.py:158
msgid "Number of Periods"
msgstr "Anzahl der Perioden"
#: django_celery_beat/models.py:159
msgid "Number of interval periods to wait before running the task again"
msgstr ""
"Anzahl der Intervallperioden, die gewartet werden sollen, bevor der Task "
"erneut ausgeführt wird"
#: django_celery_beat/models.py:165
msgid "Interval Period"
msgstr "Intervallperiode"
#: django_celery_beat/models.py:166
msgid "The type of period between task runs (Example: days)"
msgstr "Der Typ des Zeitraums zwischen den Taskläufen (Beispiel: Tage)"
#: django_celery_beat/models.py:172
msgid "interval"
msgstr "Intervall"
#: django_celery_beat/models.py:173
msgid "intervals"
msgstr "Intervalle"
#: django_celery_beat/models.py:200
msgid "every {}"
msgstr "jede {}"
#: django_celery_beat/models.py:205
msgid "every {} {}"
msgstr "jede {} {}"
#: django_celery_beat/models.py:216
msgid "Clock Time"
msgstr "Uhrzeit"
#: django_celery_beat/models.py:217
msgid "Run the task at clocked time"
msgstr "Die Aufgabe zur Uhrzeit ausführen"
#: django_celery_beat/models.py:223 django_celery_beat/models.py:224
msgid "clocked"
msgstr "Getaktet"
#: django_celery_beat/models.py:264
msgid "Minute(s)"
msgstr "Minute(n)"
#: django_celery_beat/models.py:266
msgid "Cron Minutes to Run. Use \"*\" for \"all\". (Example: \"0,30\")"
msgstr ""
"Cron Minuten zur Ausführung. Verwenden Sie \"*\" für \"alle\". (Beispiel: "
"\"0,30\")"
#: django_celery_beat/models.py:271
msgid "Hour(s)"
msgstr "Stunde(n)"
#: django_celery_beat/models.py:273
msgid "Cron Hours to Run. Use \"*\" for \"all\". (Example: \"8,20\")"
msgstr ""
"Cron Stunden zur Ausführung. Verwenden Sie \"*\" für \"alle\". (Beispiel: "
"„8,20“)"
#: django_celery_beat/models.py:278
msgid "Day(s) Of The Week"
msgstr "Tag(e) der Woche"
#: django_celery_beat/models.py:280
#, fuzzy
#| msgid ""
#| "Cron Days Of The Week to Run. Use \"*\" for \"all\". (Example: \"0,5\")"
msgid ""
"Cron Days Of The Week to Run. Use \"*\" for \"all\", Sunday is 0 or 7, "
"Monday is 1. (Example: \"0,5\")"
msgstr ""
"Cron Tage der Woche zur Ausführung. Verwenden Sie \"*\" für \"alle\", Sonntag ist 0 oder 7, "
"Montag ist 1. (Beispiel: \"0,5\")"
#: django_celery_beat/models.py:286
msgid "Day(s) Of The Month"
msgstr "Tag(e) des Monats"
#: django_celery_beat/models.py:288
msgid ""
"Cron Days Of The Month to Run. Use \"*\" for \"all\". (Example: \"1,15\")"
msgstr ""
"Cron Tage des Monats zur Ausführung. Verwenden Sie \"*\" für \"alle\". "
"(Beispiel: \"1,15\")"
#: django_celery_beat/models.py:294
msgid "Month(s) Of The Year"
msgstr "Monat(e) des Jahres"
#: django_celery_beat/models.py:296
#, fuzzy
#| msgid ""
#| "Cron Months Of The Year to Run. Use \"*\" for \"all\". (Example: \"0,6\")"
msgid ""
"Cron Months (1-12) Of The Year to Run. Use \"*\" for \"all\". (Example: "
"\"1,12\")"
msgstr ""
"Cron Monate des Jahres zur Ausführung. Verwenden Sie \"*\" für \"alle\". "
"(Beispiel: \"0,6\")"
#: django_celery_beat/models.py:304
msgid "Cron Timezone"
msgstr "Cron Zeitzone"
#: django_celery_beat/models.py:306
msgid "Timezone to Run the Cron Schedule on. Default is UTC."
msgstr ""
"Zeitzone, in der der Cron-Zeitplan ausgeführt werden soll. Der Standardwert "
"ist UTC."
#: django_celery_beat/models.py:312
msgid "crontab"
msgstr "Crontab"
#: django_celery_beat/models.py:313
msgid "crontabs"
msgstr "Crontabs"
#: django_celery_beat/models.py:404
msgid "Name"
msgstr "Name"
#: django_celery_beat/models.py:405
msgid "Short Description For This Task"
msgstr "Kurzbeschreibung für diese Aufgabe"
#: django_celery_beat/models.py:410
msgid ""
"The Name of the Celery Task that Should be Run. (Example: \"proj.tasks."
"import_contacts\")"
msgstr ""
"Der Name des Celery-Tasks, der ausgeführt werden soll. (Beispiel: \"proj."
"tasks.import_contacts\")"
#: django_celery_beat/models.py:418
msgid "Interval Schedule"
msgstr "Intervall-Zeitplan"
#: django_celery_beat/models.py:419
msgid ""
"Interval Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"Intervallzeitplan zum Ausführen der Aufgabe. Legen Sie nur einen Zeitplantyp "
"fest und lassen Sie die anderen null."
#: django_celery_beat/models.py:424
msgid "Crontab Schedule"
msgstr "Crontab-Zeitplan"
#: django_celery_beat/models.py:425
msgid ""
"Crontab Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"Crontab Zeitplan zum Ausführen der Aufgabe. Legen Sie nur einen Zeitplantyp "
"fest und lassen Sie die anderen null."
#: django_celery_beat/models.py:430
msgid "Solar Schedule"
msgstr "Solar-Zeitplan"
#: django_celery_beat/models.py:431
msgid ""
"Solar Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"Solarzeitplan, um die Aufgabe auszuführen. Legen Sie nur einen Zeitplantyp "
"fest und lassen Sie die anderen auf null."
#: django_celery_beat/models.py:436
msgid "Clocked Schedule"
msgstr "Getakteter-Zeitplan"
#: django_celery_beat/models.py:437
msgid ""
"Clocked Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"Getakteter Zeitplan zum Ausführen der Aufgabe. Legen Sie nur einen "
"Zeitplantyp fest und lassen Sie die anderen null."
#: django_celery_beat/models.py:443
msgid "Positional Arguments"
msgstr "Positionsargumente"
#: django_celery_beat/models.py:445
msgid "JSON encoded positional arguments (Example: [\"arg1\", \"arg2\"])"
msgstr "JSON-Codierte Positionsargumente (Beispiel: [\"arg1\", \"arg2\"])"
#: django_celery_beat/models.py:450
msgid "Keyword Arguments"
msgstr "Schlüsselwort-Argumente"
#: django_celery_beat/models.py:452
msgid "JSON encoded keyword arguments (Example: {\"argument\": \"value\"})"
msgstr ""
"JSON-Codierte Schlüsselwortargumente (Beispiel: {\"argument\": \"wert\"})"
#: django_celery_beat/models.py:458
msgid "Queue Override"
msgstr "Warteschlangenüberschreibung"
#: django_celery_beat/models.py:460
msgid "Queue defined in CELERY_TASK_QUEUES. Leave None for default queuing."
msgstr ""
"In CELERY_TASK_QUEUES definierte Warteschlange. Auf None lassen, für die "
"Standardwarteschlange."
#: django_celery_beat/models.py:469
msgid "Exchange"
msgstr "Exchange"
#: django_celery_beat/models.py:470
msgid "Override Exchange for low-level AMQP routing"
msgstr "Override Exchange für Low-Level-AMQP-Routing"
#: django_celery_beat/models.py:474
msgid "Routing Key"
msgstr "Routing-Schlüssel"
#: django_celery_beat/models.py:475
msgid "Override Routing Key for low-level AMQP routing"
msgstr "Override Routing Key für Low-Level-AMQP-Routing"
#: django_celery_beat/models.py:479
msgid "AMQP Message Headers"
msgstr "AMQP-Nachrichtenheader"
#: django_celery_beat/models.py:480
msgid "JSON encoded message headers for the AMQP message."
msgstr "JSON-Codierte Nachrichtenheader für die AMQP-Nachricht."
#: django_celery_beat/models.py:486
msgid "Priority"
msgstr "Priorität"
#: django_celery_beat/models.py:488
msgid ""
"Priority Number between 0 and 255. Supported by: RabbitMQ, Redis (priority "
"reversed, 0 is highest)."
msgstr ""
"Prioritätsnummer zwischen 0 und 255. Unterstützt von: RabbitMQ, Redis "
"(Priorität umgekehrt, 0 ist am höchsten)."
#: django_celery_beat/models.py:493
msgid "Expires Datetime"
msgstr "Ablaufdatum"
#: django_celery_beat/models.py:495
msgid ""
"Datetime after which the schedule will no longer trigger the task to run"
msgstr ""
"Zeitpunkt, nach dem der Zeitplan die Ausführung die Aufgabe nicht mehr "
"auslöst"
#: django_celery_beat/models.py:500
msgid "Expires timedelta with seconds"
msgstr "Ablauf-Timedelta in Sekunden"
#: django_celery_beat/models.py:502
msgid ""
"Timedelta with seconds which the schedule will no longer trigger the task to "
"run"
msgstr ""
"Timedelta in Sekunden, die der Zeitplan nicht mehr auslöst, um die Aufgabe "
"auszuführen"
#: django_celery_beat/models.py:508
msgid "One-off Task"
msgstr "Einmalige Aufgabe"
#: django_celery_beat/models.py:510
msgid "If True, the schedule will only run the task a single time"
msgstr "Wenn aktiv, wird die Aufgabe im Zeitplan nur einmal ausgeführt"
#: django_celery_beat/models.py:514
msgid "Start Datetime"
msgstr "Start-Datum"
#: django_celery_beat/models.py:516
msgid "Datetime when the schedule should begin triggering the task to run"
msgstr ""
"Zeitpunkt, zu der der Zeitplan beginnen soll, die Ausführung der Aufgabe "
"auszulösen"
#: django_celery_beat/models.py:521
msgid "Enabled"
msgstr "Aktiviert"
#: django_celery_beat/models.py:522
msgid "Set to False to disable the schedule"
msgstr "Deaktivieren zum deaktivieren -_-"
#: django_celery_beat/models.py:527
msgid "Last Run Datetime"
msgstr "Uhrzeit der letzten Ausführung"
#: django_celery_beat/models.py:529
msgid ""
"Datetime that the schedule last triggered the task to run. Reset to None if "
"enabled is set to False."
msgstr ""
"Uhrzeit, zu der der letzte Zeitplan die Ausführung die Aufgabe ausgelöst "
"hat. Setzt auf Keine zurück, wenn \"Aktiviert\" ist auf False gesetzt wird."
#: django_celery_beat/models.py:534
msgid "Total Run Count"
msgstr "Gesamtzahl der Durchgänge"
#: django_celery_beat/models.py:536
msgid "Running count of how many times the schedule has triggered the task"
msgstr "Laufende Zählung, wie oft der Zeitplan die Aufgabe ausgelöst hat"
#: django_celery_beat/models.py:541
msgid "Last Modified"
msgstr "Zuletzt geändert"
#: django_celery_beat/models.py:542
msgid "Datetime that this PeriodicTask was last modified"
msgstr "Uhrzeit zu dem diese periodische Aufgabe zuletzt modifiziert wurde"
#: django_celery_beat/models.py:546
msgid "Description"
msgstr "Beschreibung"
#: django_celery_beat/models.py:548
msgid "Detailed description about the details of this Periodic Task"
msgstr "Detaillierte Beschreibung der Details dieser periodischen Aufgabe"
#: django_celery_beat/models.py:557
msgid "periodic task"
msgstr "Periodische Aufgabe"
#: django_celery_beat/models.py:558
msgid "periodic tasks"
msgstr "Periodische Aufgaben"
#: django_celery_beat/templates/admin/djcelery/change_list.html:6
msgid "Home"
msgstr "Start"

View File

@@ -0,0 +1,528 @@
# Spanish translation strings for django-celery-beat.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# <mondejar1994@gmail.com>, 2020.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-04-04 01:30+0000\n"
"PO-Revision-Date: 2022-10-14 23:48+0200\n"
"Last-Translator: Luis Saavedra <luis94855510@gmail.com>\n"
"Language-Team: \n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Generator: Poedit 3.1.1\n"
#: django_celery_beat/admin.py:64
msgid "Task (registered)"
msgstr "Tarea (registrada)"
#: django_celery_beat/admin.py:68
msgid "Task (custom)"
msgstr "Tarea (personalizada)"
#: django_celery_beat/admin.py:85
msgid "Need name of task"
msgstr "Nombre de tarea necesario"
#: django_celery_beat/admin.py:91 django_celery_beat/models.py:586
msgid "Only one can be set, in expires and expire_seconds"
msgstr ""
"Sólo uno de los campos puede ser definido, en expiración y segundos de "
"expiración"
#: django_celery_beat/admin.py:101
#, python-format
msgid "Unable to parse JSON: %s"
msgstr "Incapaz de parsear el JSON: %s"
#: django_celery_beat/admin.py:167
#, python-brace-format
msgid "{0} task{1} {2} successfully {3}"
msgstr "{0} tarea{1} {2} correctamente {3}"
#: django_celery_beat/admin.py:170 django_celery_beat/admin.py:232
msgid "was,were"
msgstr "fue,fueron"
#: django_celery_beat/admin.py:179
msgid "Enable selected tasks"
msgstr "Habilitar tareas seleccionadas"
#: django_celery_beat/admin.py:185
msgid "Disable selected tasks"
msgstr "Deshabilitar tareas seleccionadas"
#: django_celery_beat/admin.py:197
msgid "Toggle activity of selected tasks"
msgstr "Conmutar actividad de las tareas seleccionadas"
#: django_celery_beat/admin.py:217
#, python-brace-format
msgid "task \"{0}\" not found"
msgstr "tarea \"{0}\" no encontrada"
#: django_celery_beat/admin.py:229
#, python-brace-format
msgid "{0} task{1} {2} successfully run"
msgstr "{0} tarea{1} {2} correctamente ejecutadas"
#: django_celery_beat/admin.py:235
msgid "Run selected tasks"
msgstr "Ejecutar tareas seleccionadas"
#: django_celery_beat/apps.py:13
msgid "Periodic Tasks"
msgstr "Tareas Periódicas"
#: django_celery_beat/models.py:26
msgid "Days"
msgstr "Días"
#: django_celery_beat/models.py:27
msgid "Hours"
msgstr "Horas"
#: django_celery_beat/models.py:28
msgid "Minutes"
msgstr "Minutos"
#: django_celery_beat/models.py:29
msgid "Seconds"
msgstr "Segundos"
#: django_celery_beat/models.py:30
msgid "Microseconds"
msgstr "Microsegundos"
#: django_celery_beat/models.py:34
msgid "Day"
msgstr "Día"
#: django_celery_beat/models.py:35
msgid "Hour"
msgstr "Hora"
#: django_celery_beat/models.py:36
msgid "Minute"
msgstr "Minuto"
#: django_celery_beat/models.py:37
msgid "Second"
msgstr "Segundo"
#: django_celery_beat/models.py:38
msgid "Microsecond"
msgstr "Microsegundo"
#: django_celery_beat/models.py:42
msgid "Astronomical dawn"
msgstr "Amanecer astronómico"
#: django_celery_beat/models.py:43
msgid "Civil dawn"
msgstr "Amanecer civil"
#: django_celery_beat/models.py:44
msgid "Nautical dawn"
msgstr "Amanecer náutico"
#: django_celery_beat/models.py:45
msgid "Astronomical dusk"
msgstr "Anochecer astronómico"
#: django_celery_beat/models.py:46
msgid "Civil dusk"
msgstr "Anochecer civil"
#: django_celery_beat/models.py:47
msgid "Nautical dusk"
msgstr "Anochecer náutico"
#: django_celery_beat/models.py:48
msgid "Solar noon"
msgstr "Mediodía solar"
#: django_celery_beat/models.py:49
msgid "Sunrise"
msgstr "Amanecer"
#: django_celery_beat/models.py:50
msgid "Sunset"
msgstr "Puesta de sol"
#: django_celery_beat/models.py:84
msgid "Solar Event"
msgstr "Evento Solar"
#: django_celery_beat/models.py:85
msgid "The type of solar event when the job should run"
msgstr "El tipo de evento solar cuando el proceso debe ejecutarse"
#: django_celery_beat/models.py:89
msgid "Latitude"
msgstr "Latitud"
#: django_celery_beat/models.py:90
msgid "Run the task when the event happens at this latitude"
msgstr "Ejecutar la tarea cuando el evento ocurra a esta latitud"
#: django_celery_beat/models.py:95
msgid "Longitude"
msgstr "Longitud"
#: django_celery_beat/models.py:96
msgid "Run the task when the event happens at this longitude"
msgstr "Ejecutar la tarea cuando el evento ocurra a esta longitud"
#: django_celery_beat/models.py:103
msgid "solar event"
msgstr "evento solar"
#: django_celery_beat/models.py:104
msgid "solar events"
msgstr "eventos solares"
#: django_celery_beat/models.py:153
msgid "Number of Periods"
msgstr "Número de Períodos"
#: django_celery_beat/models.py:154
msgid "Number of interval periods to wait before running the task again"
msgstr ""
"Número de períodos de intervalo a esperar antes de ejecutar esta tarea de "
"nuevo"
#: django_celery_beat/models.py:160
msgid "Interval Period"
msgstr "Período de intervalo"
#: django_celery_beat/models.py:161
msgid "The type of period between task runs (Example: days)"
msgstr "El tipo de período entre ejecuciones de tarea (Ejemplo: días)"
#: django_celery_beat/models.py:167
msgid "interval"
msgstr "intervalo"
#: django_celery_beat/models.py:168
msgid "intervals"
msgstr "intervalos"
#: django_celery_beat/models.py:195
msgid "every {}"
msgstr "cada {}"
#: django_celery_beat/models.py:200
msgid "every {} {}"
msgstr "cada {} {}"
#: django_celery_beat/models.py:211
msgid "Clock Time"
msgstr "Hora y día"
#: django_celery_beat/models.py:212
msgid "Run the task at clocked time"
msgstr "Ejecuta la tarea en el momento indicado"
#: django_celery_beat/models.py:218 django_celery_beat/models.py:219
msgid "clocked"
msgstr "cronometrado"
#: django_celery_beat/models.py:258
msgid "Minute(s)"
msgstr "Minuto(s)"
#: django_celery_beat/models.py:260
msgid "Cron Minutes to Run. Use \"*\" for \"all\". (Example: \"0,30\")"
msgstr ""
"Minutos Cron cuando ejecutar. Usa \"*\" para \"todos\". (Ejemplo: \"0,30\")"
#: django_celery_beat/models.py:265
msgid "Hour(s)"
msgstr "Hora(s)"
#: django_celery_beat/models.py:267
msgid "Cron Hours to Run. Use \"*\" for \"all\". (Example: \"8,20\")"
msgstr ""
"Horas Cron cuando ejecutar. Usa \"*\" para \"todas\". (Ejemplo: \"8,20\")"
#: django_celery_beat/models.py:272
msgid "Day(s) Of The Week"
msgstr "Día(s) de la semana"
#: django_celery_beat/models.py:274
msgid "Cron Days Of The Week to Run. Use \"*\" for \"all\", Sunday is 0 or 7, Monday is 1. (Example: \"0,5\")"
msgstr ""
"Días de la semana Cron cuando ejecutar. Usa \"*\" para \"todos\", Domingo es 0 o 7, Lunes es 1. (Ejemplo: "
"\"0,5\")"
#: django_celery_beat/models.py:280
msgid "Day(s) Of The Month"
msgstr "Día(s) del mes"
#: django_celery_beat/models.py:282
msgid ""
"Cron Days Of The Month to Run. Use \"*\" for \"all\". (Example: \"1,15\")"
msgstr ""
"Días del mes Cron cuando ejecutar. Usa \"*\" para \"todos\". (Ejemplo: "
"\"1,15\")"
#: django_celery_beat/models.py:288
msgid "Month(s) Of The Year"
msgstr "Mes(es) del año"
#: django_celery_beat/models.py:290
msgid ""
"Cron Months Of The Year to Run. Use \"*\" for \"all\". (Example: \"0,6\")"
msgstr ""
"Meses del año Cron cuando ejecutar. Usa \"*\" para \"todos\". (Ejemplo: "
"\"0,6\")"
#: django_celery_beat/models.py:297
msgid "Cron Timezone"
msgstr "Zona horaria Cron"
#: django_celery_beat/models.py:299
msgid "Timezone to Run the Cron Schedule on. Default is UTC."
msgstr "Zona horaria donde ejecutar la programación Cron. Por defecto UTC."
#: django_celery_beat/models.py:305
msgid "crontab"
msgstr "crontab"
#: django_celery_beat/models.py:306
msgid "crontabs"
msgstr "crontabs"
#: django_celery_beat/models.py:390
msgid "Name"
msgstr "Nombre"
#: django_celery_beat/models.py:391
msgid "Short Description For This Task"
msgstr "Descripción corta para esta tarea"
#: django_celery_beat/models.py:396
msgid ""
"The Name of the Celery Task that Should be Run. (Example: \"proj.tasks."
"import_contacts\")"
msgstr ""
"Nombre de la tarea Celery que debe ser ejecutada. (Ejemplo: \"proj.tasks."
"import_contacts\")"
#: django_celery_beat/models.py:404
msgid "Interval Schedule"
msgstr "Intervalo de programación"
#: django_celery_beat/models.py:405
msgid ""
"Interval Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"Intervalo de programación donde ejecutar la tarea. Establece sólo un tipo de "
"programación, deja el resto en blanco."
#: django_celery_beat/models.py:410
msgid "Crontab Schedule"
msgstr "Programación Crontab"
#: django_celery_beat/models.py:411
msgid ""
"Crontab Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"Programación Crontab con la cual ejecutar la tarea. Establece sólo un tipo "
"de programación, deja el resto en blanco."
#: django_celery_beat/models.py:416
msgid "Solar Schedule"
msgstr "Programación solar"
#: django_celery_beat/models.py:417
msgid ""
"Solar Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"Programación solar con la cual ejecutar la tarea. Establece sólo un tipo de "
"programación, deja el resto en blanco."
#: django_celery_beat/models.py:422
msgid "Clocked Schedule"
msgstr "Programación horaria"
#: django_celery_beat/models.py:423
msgid ""
"Clocked Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"Programación horaria con la cual ejecutar la tarea. Establece sólo un tipo "
"de programación, deja el resto en blanco."
#: django_celery_beat/models.py:429
msgid "Positional Arguments"
msgstr "Argumentos posicionales"
#: django_celery_beat/models.py:431
msgid "JSON encoded positional arguments (Example: [\"arg1\", \"arg2\"])"
msgstr ""
"Argumentos posicionales codificados en formato JSON. (Ejemplo: [\"arg1\", "
"\"arg2\"])"
#: django_celery_beat/models.py:436
msgid "Keyword Arguments"
msgstr "Agumentos opcionales"
#: django_celery_beat/models.py:438
msgid "JSON encoded keyword arguments (Example: {\"argument\": \"value\"})"
msgstr ""
"Argumentos opcionales codificados en formato JSON. (Ejemplo: {\"argument\": "
"\"value\"})"
#: django_celery_beat/models.py:444
msgid "Queue Override"
msgstr "Invalidación de cola"
#: django_celery_beat/models.py:446
msgid "Queue defined in CELERY_TASK_QUEUES. Leave None for default queuing."
msgstr ""
"Cola definida en CELERY_TASK_QUEUES. Dejala nula para la cola por defecto."
#: django_celery_beat/models.py:455
msgid "Exchange"
msgstr "Intercambio"
#: django_celery_beat/models.py:456
msgid "Override Exchange for low-level AMQP routing"
msgstr "Invalida intercambio para enrutamiento de bajo nivel de AMQP"
#: django_celery_beat/models.py:460
msgid "Routing Key"
msgstr "Clave de enrutamiento"
#: django_celery_beat/models.py:461
msgid "Override Routing Key for low-level AMQP routing"
msgstr ""
"Invalida la clave de enrutamiento para enrutamiento de bajo nivel de AMQP"
#: django_celery_beat/models.py:465
msgid "AMQP Message Headers"
msgstr "Cabeceras de mensaje de AMQP"
#: django_celery_beat/models.py:466
msgid "JSON encoded message headers for the AMQP message."
msgstr "Cacbeceras de mensaje de AMQP codificadas en formato JSON."
#: django_celery_beat/models.py:472
msgid "Priority"
msgstr "Prioridad"
#: django_celery_beat/models.py:474
msgid ""
"Priority Number between 0 and 255. Supported by: RabbitMQ, Redis (priority "
"reversed, 0 is highest)."
msgstr ""
"Número de prioridad entre 0 and 255. Soportado por: RabbitMQ, Redis "
"(prioridad invertida, 0 es la más alta)."
#: django_celery_beat/models.py:479
msgid "Expires Datetime"
msgstr "Fecha de caducidad"
#: django_celery_beat/models.py:481
msgid ""
"Datetime after which the schedule will no longer trigger the task to run"
msgstr ""
"Fecha después de la cual la programación no provocará que la tarea vuelva a "
"ejecutarse"
#: django_celery_beat/models.py:486
msgid "Expires timedelta with seconds"
msgstr "Delta de tiempo de expiración en segundos"
#: django_celery_beat/models.py:488
msgid ""
"Timedelta with seconds which the schedule will no longer trigger the task to "
"run"
msgstr ""
"Delta de Tiempo en segundos después de los cuales la programación no "
"provocará que la tarea vuelva a ejecutarse"
#: django_celery_beat/models.py:494
msgid "One-off Task"
msgstr "Tarea de ejecución única"
#: django_celery_beat/models.py:496
msgid "If True, the schedule will only run the task a single time"
msgstr "Si es verdadera, la programación sólo lanzará la tarea una vez"
#: django_celery_beat/models.py:500
msgid "Start Datetime"
msgstr "Fecha de comienzo"
#: django_celery_beat/models.py:502
msgid "Datetime when the schedule should begin triggering the task to run"
msgstr ""
"Fecha cuando la programación debe comenzar a provocar la ejecución de la "
"tarea"
#: django_celery_beat/models.py:507
msgid "Enabled"
msgstr "Habilitada"
#: django_celery_beat/models.py:508
msgid "Set to False to disable the schedule"
msgstr "Establece a Falso para deshabilitar la programación"
#: django_celery_beat/models.py:513
msgid "Last Run Datetime"
msgstr "Fecha de última ejecución"
#: django_celery_beat/models.py:515
msgid ""
"Datetime that the schedule last triggered the task to run. Reset to None if "
"enabled is set to False."
msgstr ""
"Fecha en la cual la programación ejecutó la tarea por última vez. "
"Reinicializa a None si enabled está establecido como falso."
#: django_celery_beat/models.py:520
msgid "Total Run Count"
msgstr "Contador de ejecuciones totales"
#: django_celery_beat/models.py:522
msgid "Running count of how many times the schedule has triggered the task"
msgstr "Contador de cuentas veces ha sido ejecutada la tarea"
#: django_celery_beat/models.py:527
msgid "Last Modified"
msgstr "Última modificación"
#: django_celery_beat/models.py:528
msgid "Datetime that this PeriodicTask was last modified"
msgstr "Fecha en la cual esta tarea periódica fue modificada por última vez"
#: django_celery_beat/models.py:532
msgid "Description"
msgstr "Descripción"
#: django_celery_beat/models.py:534
msgid "Detailed description about the details of this Periodic Task"
msgstr "Descripción detallada sobre los detalles de esta tarea periódica"
#: django_celery_beat/models.py:543
msgid "periodic task"
msgstr "tarea periódica"
#: django_celery_beat/models.py:544
msgid "periodic tasks"
msgstr "tareas periódicas"
#: django_celery_beat/templates/admin/djcelery/change_list.html:6
msgid "Home"
msgstr "Inicio"

View File

@@ -0,0 +1,534 @@
# Farsi translation strings for django-celery-beat.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <<hamidfzm@gmail.com>, 2023.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-10-20 18:28+0000\n"
"PO-Revision-Date: 2023-10-20 19:03+0000\n"
"Last-Translator: Hamid FzM <hamidfzm@gmail.com>\n"
"Language-Team: \n"
"Language: fa\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: django_celery_beat/admin.py:60
msgid "Task (registered)"
msgstr "تسک (ثبت شده)"
#: django_celery_beat/admin.py:64
msgid "Task (custom)"
msgstr "تسک (سفارشی)"
#: django_celery_beat/admin.py:81
msgid "Need name of task"
msgstr "به نام تسک نیاز دارد"
#: django_celery_beat/admin.py:87 django_celery_beat/models.py:614
msgid "Only one can be set, in expires and expire_seconds"
msgstr "بین expires و expire_seconds فقط یکی می تواند تنظیم شود"
#: django_celery_beat/admin.py:97
#, python-format
msgid "Unable to parse JSON: %s"
msgstr "امکان تجزیه JSON وجود ندارد: %s"
#: django_celery_beat/admin.py:125
msgid "Schedule"
msgstr "برنامه‌ریزی"
#: django_celery_beat/admin.py:130
msgid "Arguments"
msgstr "آرگومان‌ها"
#: django_celery_beat/admin.py:134
msgid "Execution Options"
msgstr "گزینه‌های اجرا"
#: django_celery_beat/admin.py:179
#, python-brace-format
msgid "{0} task{1} {2} successfully {3}"
msgstr "{0} تسک{1} {2} با موفقیت {3}"
#: django_celery_beat/admin.py:182 django_celery_beat/admin.py:249
msgid "was,were"
msgstr "بود,بودند"
#: django_celery_beat/admin.py:191
msgid "Enable selected tasks"
msgstr "فعال کردن تسک‌های انتخاب شده"
#: django_celery_beat/admin.py:197
msgid "Disable selected tasks"
msgstr "غیرفعال کردن تسک‌های انتخاب شده"
#: django_celery_beat/admin.py:209
msgid "Toggle activity of selected tasks"
msgstr "تغییر فعالیت تسک‌های انتخاب شده"
#: django_celery_beat/admin.py:230
#, fuzzy, python-brace-format
#| msgid "task \"{0}\" not found"
msgid "task \"{not_found_task_name}\" not found"
msgstr "تسک \"{not_found_task_name}\" یافت نشد"
#: django_celery_beat/admin.py:246
#, python-brace-format
msgid "{0} task{1} {2} successfully run"
msgstr "{0} تسک{1} {2} با موفقیت اجرا شد"
#: django_celery_beat/admin.py:252
msgid "Run selected tasks"
msgstr "اجرای تسک‌های انتخاب شده"
#: django_celery_beat/apps.py:13
msgid "Periodic Tasks"
msgstr "تسک‌های دوره‌ای"
#: django_celery_beat/models.py:31
msgid "Days"
msgstr "روزها"
#: django_celery_beat/models.py:32
msgid "Hours"
msgstr "ساعت‌ها"
#: django_celery_beat/models.py:33
msgid "Minutes"
msgstr "دقیقه‌ها"
#: django_celery_beat/models.py:34
msgid "Seconds"
msgstr "ثانیه‌ها"
#: django_celery_beat/models.py:35
msgid "Microseconds"
msgstr "میکروثانیه‌ها"
#: django_celery_beat/models.py:39
msgid "Day"
msgstr "روز"
#: django_celery_beat/models.py:40
msgid "Hour"
msgstr "ساعت"
#: django_celery_beat/models.py:41
msgid "Minute"
msgstr "دقیقه"
#: django_celery_beat/models.py:42
msgid "Second"
msgstr "ثانیه"
#: django_celery_beat/models.py:43
msgid "Microsecond"
msgstr "میکروثانیه"
#: django_celery_beat/models.py:47
msgid "Astronomical dawn"
msgstr "طلوع نجومی"
#: django_celery_beat/models.py:48
msgid "Civil dawn"
msgstr "طلوع مدنی"
#: django_celery_beat/models.py:49
msgid "Nautical dawn"
msgstr "طلوع دریایی"
#: django_celery_beat/models.py:50
msgid "Astronomical dusk"
msgstr "غروب نجومی"
#: django_celery_beat/models.py:51
msgid "Civil dusk"
msgstr "غروب مدنی"
#: django_celery_beat/models.py:52
msgid "Nautical dusk"
msgstr "غروب دریایی"
#: django_celery_beat/models.py:53
msgid "Solar noon"
msgstr "ظهر خورشیدی"
#: django_celery_beat/models.py:54
msgid "Sunrise"
msgstr "طلوع خورشیدی"
#: django_celery_beat/models.py:55
msgid "Sunset"
msgstr "غروب خورشیدی"
#: django_celery_beat/models.py:89
msgid "Solar Event"
msgstr "رویداد خورشیدی"
#: django_celery_beat/models.py:90
msgid "The type of solar event when the job should run"
msgstr "نوع رویداد خورشیدی زمانی که کار باید اجرا شود"
#: django_celery_beat/models.py:94
msgid "Latitude"
msgstr "عرض جغرافیایی"
#: django_celery_beat/models.py:95
msgid "Run the task when the event happens at this latitude"
msgstr "هنگامی که رویداد در این عرض جغرافیایی اتفاق می افتد، تسک را اجرا کن"
#: django_celery_beat/models.py:100
msgid "Longitude"
msgstr "طول جغرافیایی"
#: django_celery_beat/models.py:101
msgid "Run the task when the event happens at this longitude"
msgstr "هنگامی که رویداد در این طول جغرافیایی اتفاق می افتد، تسک را اجرا کن"
#: django_celery_beat/models.py:108
msgid "solar event"
msgstr "رویداد خورشیدی"
#: django_celery_beat/models.py:109
msgid "solar events"
msgstr "رویدادهای خورشیدی"
#: django_celery_beat/models.py:159
msgid "Number of Periods"
msgstr "تعداد دوره‌ها"
#: django_celery_beat/models.py:160
msgid "Number of interval periods to wait before running the task again"
msgstr "تعداد بازه‌های زمانی برای انتظار قبل از اجرای دوباره تسک"
#: django_celery_beat/models.py:166
msgid "Interval Period"
msgstr "دوره فاصله زمانی"
#: django_celery_beat/models.py:167
msgid "The type of period between task runs (Example: days)"
msgstr "نوع دوره بین اجرای تسک (مثال: روزها)"
#: django_celery_beat/models.py:173
msgid "interval"
msgstr "فاصله زمانی"
#: django_celery_beat/models.py:174
msgid "intervals"
msgstr "فاصله‌های زمانی"
#: django_celery_beat/models.py:201
msgid "every {}"
msgstr "هر {}"
#: django_celery_beat/models.py:206
msgid "every {} {}"
msgstr "هر {} {}"
#: django_celery_beat/models.py:217
msgid "Clock Time"
msgstr "زمان ساعت"
#: django_celery_beat/models.py:218
msgid "Run the task at clocked time"
msgstr "تسک را در زمان مشخص شده اجرا کن"
#: django_celery_beat/models.py:224 django_celery_beat/models.py:225
msgid "clocked"
msgstr "ساعت مشخص شده"
#: django_celery_beat/models.py:265
msgid "Minute(s)"
msgstr "دقیقه‌(ها)"
#: django_celery_beat/models.py:267
msgid "Cron Minutes to Run. Use \"*\" for \"all\". (Example: \"0,30\")"
msgstr ""
"کرون دقیقه‌هایی که باید اجرا شوند. برای \"همه\" از \"*\" استفاده کنید. (مثال: "
"\"0,30\")"
#: django_celery_beat/models.py:272
msgid "Hour(s)"
msgstr "ساعت‌(ها)"
#: django_celery_beat/models.py:274
msgid "Cron Hours to Run. Use \"*\" for \"all\". (Example: \"8,20\")"
msgstr ""
"کرون ساعت‌هایی که باید اجرا شوند. برای \"همه\" از \"*\" استفاده کنید. (مثال: "
"\"8,20\")"
#: django_celery_beat/models.py:279
msgid "Day(s) Of The Week"
msgstr "روز(های) هفته"
#: django_celery_beat/models.py:281
#, fuzzy
#| msgid ""
#| "Cron Days Of The Week to Run. Use \"*\" for \"all\". (Example: \"0,5\")"
msgid ""
"Cron Days Of The Week to Run. Use \"*\" for \"all\", Sunday is 0 or 7, "
"Monday is 1. (Example: \"0,5\")"
msgstr ""
"کرون روزهای هفته‌ای که باید اجرا شوند. برای \"همه\" از \"*\" استفاده کنید. "
"یکشنبه 0 یا 7 است، دوشنبه 1. (مثال: \"0,5\")"
#: django_celery_beat/models.py:287
msgid "Day(s) Of The Month"
msgstr "روز(های) ماه"
#: django_celery_beat/models.py:289
msgid ""
"Cron Days Of The Month to Run. Use \"*\" for \"all\". (Example: \"1,15\")"
msgstr ""
"کرون روزهای ماهیانه که باید اجرا شوند. برای \"همه\" از \"*\" استفاده کنید. "
"(مثال: \"1,15\")"
#: django_celery_beat/models.py:295
msgid "Month(s) Of The Year"
msgstr "ماه(های) سال"
#: django_celery_beat/models.py:297
#, fuzzy
#| msgid ""
#| "Cron Months Of The Year to Run. Use \"*\" for \"all\". (Example: \"0,6\")"
msgid ""
"Cron Months (1-12) Of The Year to Run. Use \"*\" for \"all\". (Example: "
"\"1,12\")"
msgstr ""
"کرون ماه‌های سالی که باید اجرا شوند. برای \"همه\" از \"*\" استفاده کنید. "
"(مثال: \"0,6\")"
#: django_celery_beat/models.py:305
msgid "Cron Timezone"
msgstr "منطقه زمانی کرون"
#: django_celery_beat/models.py:307
msgid "Timezone to Run the Cron Schedule on. Default is UTC."
msgstr "منطقه زمانی برای اجرای برنامه زمانی کرون. پیش فرض UTC است."
#: django_celery_beat/models.py:313
msgid "crontab"
msgstr "کرون‌تب"
#: django_celery_beat/models.py:314
msgid "crontabs"
msgstr "کرون‌تب‌ها"
#: django_celery_beat/models.py:413
msgid "Name"
msgstr "نام"
#: django_celery_beat/models.py:414
msgid "Short Description For This Task"
msgstr "توضیحات کوتاه برای این تسک"
#: django_celery_beat/models.py:419
msgid ""
"The Name of the Celery Task that Should be Run. (Example: \"proj.tasks."
"import_contacts\")"
msgstr "نام تسک سلری که باید اجرا شود. (مثال: \"proj.tasks.import_contacts\")"
#: django_celery_beat/models.py:427
msgid "Interval Schedule"
msgstr "فاصله زمانی برنامه‌ریزی"
#: django_celery_beat/models.py:428
msgid ""
"Interval Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"فاصله زمانی برنامه‌ریزی برای اجرای تسک. فقط یک نوع برنامه‌ریزی را تنظیم کنید، "
"باقی را خالی بگذارید."
#: django_celery_beat/models.py:433
msgid "Crontab Schedule"
msgstr "برنامه‌ریزی کرون‌تب"
#: django_celery_beat/models.py:434
msgid ""
"Crontab Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"برنامه‌ریزی کرون‌تب برای اجرای تسک. فقط یک نوع برنامه‌ریزی را تنظیم کنید، باقی "
"را خالی بگذارید."
#: django_celery_beat/models.py:439
msgid "Solar Schedule"
msgstr "برنامه‌ریزی خورشیدی"
#: django_celery_beat/models.py:440
msgid ""
"Solar Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"برنامه‌ریزی خورشیدی برای اجرای تسک. فقط یک نوع برنامه‌ریزی را تنظیم کنید، باقی "
"را خالی بگذارید."
#: django_celery_beat/models.py:445
msgid "Clocked Schedule"
msgstr "برنامه‌ریزی ساعتی"
#: django_celery_beat/models.py:446
msgid ""
"Clocked Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"برنامه‌ریزی ساعتی برای اجرای تسک. فقط یک نوع برنامه‌ریزی را تنظیم کنید، باقی "
"را خالی بگذارید."
#: django_celery_beat/models.py:452
msgid "Positional Arguments"
msgstr "آرگومان‌های موقعیتی"
#: django_celery_beat/models.py:454
msgid "JSON encoded positional arguments (Example: [\"arg1\", \"arg2\"])"
msgstr "آرگومان‌های موقعیتی اینکود شده JSON (مثال: [\"arg1\", \"arg2\"])"
#: django_celery_beat/models.py:459
msgid "Keyword Arguments"
msgstr "آرگومان‌های کلیدواژه‌ای"
#: django_celery_beat/models.py:461
msgid "JSON encoded keyword arguments (Example: {\"argument\": \"value\"})"
msgstr ""
"آرگومان‌های کلیدواژه‌ای اینکود شده JSON (مثال: {\"argument\": \"value\"})"
#: django_celery_beat/models.py:467
msgid "Queue Override"
msgstr "تغییر صف"
#: django_celery_beat/models.py:469
msgid "Queue defined in CELERY_TASK_QUEUES. Leave None for default queuing."
msgstr "صف تعریف شده در CELERY_TASK_QUEUES. برای صف پیش فرض، خالی بگذارید."
#: django_celery_beat/models.py:478
msgid "Exchange"
msgstr "تبادل"
#: django_celery_beat/models.py:479
msgid "Override Exchange for low-level AMQP routing"
msgstr "تغییر تبادل برای مسیریابی AMQP سطح پایین"
#: django_celery_beat/models.py:483
msgid "Routing Key"
msgstr "کلید مسیریابی"
#: django_celery_beat/models.py:484
msgid "Override Routing Key for low-level AMQP routing"
msgstr "تغییر کلید مسیریابی برای مسیریابی AMQP سطح پایین"
#: django_celery_beat/models.py:488
msgid "AMQP Message Headers"
msgstr "هدرهای پیام AMQP"
#: django_celery_beat/models.py:489
msgid "JSON encoded message headers for the AMQP message."
msgstr "پیام اینکود شده JSON برای پیام AMQP."
#: django_celery_beat/models.py:495
msgid "Priority"
msgstr "اولویت"
#: django_celery_beat/models.py:497
msgid ""
"Priority Number between 0 and 255. Supported by: RabbitMQ, Redis (priority "
"reversed, 0 is highest)."
msgstr ""
"عدد اولویت بین 0 و 255. پشتیبانی از: RabbitMQ, Redis (اولویت معکوس، 0 "
"بالاترین است)."
#: django_celery_beat/models.py:502
msgid "Expires Datetime"
msgstr "تاریخ انقضا"
#: django_celery_beat/models.py:504
msgid ""
"Datetime after which the schedule will no longer trigger the task to run"
msgstr "تاریخی که برنامه‌ریزی دیگر تسک را آغاز نمی کند"
#: django_celery_beat/models.py:509
msgid "Expires timedelta with seconds"
msgstr "مدت زمان به ثانیه که منقضی می شود"
#: django_celery_beat/models.py:511
msgid ""
"Timedelta with seconds which the schedule will no longer trigger the task to "
"run"
msgstr "مدت زمان به ثانیه که برنامه‌ریزی تسک را دیگر آغاز نمی کند"
#: django_celery_beat/models.py:517
msgid "One-off Task"
msgstr "تسک یک مرتبه‌ای"
#: django_celery_beat/models.py:519
msgid "If True, the schedule will only run the task a single time"
msgstr "اگر درست باشد، برنامه‌ریزی فقط یک بار تسک را اجرا می کند"
#: django_celery_beat/models.py:523
msgid "Start Datetime"
msgstr "تاریخ شروع"
#: django_celery_beat/models.py:525
msgid "Datetime when the schedule should begin triggering the task to run"
msgstr "تاریخی که برنامه‌ریزی باید شروع به اجرای تسک کند"
#: django_celery_beat/models.py:530
msgid "Enabled"
msgstr "فعال"
#: django_celery_beat/models.py:531
msgid "Set to False to disable the schedule"
msgstr "برای غیرفعال کردن برنامه‌ریزی، روی نادرست تنظیم کنید"
#: django_celery_beat/models.py:536
msgid "Last Run Datetime"
msgstr "آخرین تاریخ اجرا"
#: django_celery_beat/models.py:538
msgid ""
"Datetime that the schedule last triggered the task to run. Reset to None if "
"enabled is set to False."
msgstr ""
"تاریخی که برنامه‌ریزی آخرین بار تسک را آغاز کرده است. اگر فعال را روی نادرست "
"تنظیم کنید، به None تنظیم می شود."
#: django_celery_beat/models.py:543
msgid "Total Run Count"
msgstr "تعداد کل اجرا"
#: django_celery_beat/models.py:545
msgid "Running count of how many times the schedule has triggered the task"
msgstr "تعداد دفعاتی که برنامه‌ریزی تسک را آغاز کرده است"
#: django_celery_beat/models.py:550
msgid "Last Modified"
msgstr "آخرین ویرایش"
#: django_celery_beat/models.py:551
msgid "Datetime that this PeriodicTask was last modified"
msgstr "تاریخی که این تسک دوره‌ای آخرین بار ویرایش شده است"
#: django_celery_beat/models.py:555
msgid "Description"
msgstr "توضیحات"
#: django_celery_beat/models.py:557
msgid "Detailed description about the details of this Periodic Task"
msgstr "توضیحات دقیق در مورد این تسک دوره‌ای"
#: django_celery_beat/models.py:566
msgid "periodic task"
msgstr "تسک دوره‌ای"
#: django_celery_beat/models.py:567
msgid "periodic tasks"
msgstr "تسک‌های دوره‌ای"
#: django_celery_beat/templates/admin/djcelery/change_list.html:6
msgid "Home"
msgstr "خانه"

View File

@@ -0,0 +1,555 @@
# French translation strings for django-celery-beat.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# <flow.gunso@gmail.com>, 2019.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-12-22 19:03+0000\n"
"PO-Revision-Date: 2024-06-25 11:24+0200\n"
"Last-Translator: Álvaro Mondéjar <mondejar1994@gmail.com>\n"
"Language-Team: nLanguage: fr\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: django_celery_beat/admin.py:61
msgid "Task (registered)"
msgstr "Tâche (enregistrée)"
#: django_celery_beat/admin.py:65
msgid "Task (custom)"
msgstr "Tâche (personalisée)"
#: django_celery_beat/admin.py:82
msgid "Need name of task"
msgstr "Besoin du nom de la tâche"
#: django_celery_beat/admin.py:88 django_celery_beat/models.py:626
msgid "Only one can be set, in expires and expire_seconds"
msgstr "Seulement un peu être définie, soit expires ou expire_seconds"
#: django_celery_beat/admin.py:98
#, python-format
msgid "Unable to parse JSON: %s"
msgstr "Incapable d'analyser le JSON: %s"
#: django_celery_beat/admin.py:127
msgid "Schedule"
msgstr "Planification"
#: django_celery_beat/admin.py:132
msgid "Arguments"
msgstr "Arguments"
#: django_celery_beat/admin.py:136
msgid "Execution Options"
msgstr "Options d'exécution"
#: django_celery_beat/admin.py:174
msgid "Enable selected tasks"
msgstr "Active les tâches sélectionnées"
#: django_celery_beat/admin.py:182
#, python-brace-format
msgid "{0} task was successfully enabled"
msgid_plural "{0} tasks were successfully enabled"
msgstr[0] "{0} tâche a été activée avec succès"
msgstr[1] "{0} tâches ont été activées avec succès"
#: django_celery_beat/admin.py:189
msgid "Disable selected tasks"
msgstr "Désactive les tâches sélectionnées"
#: django_celery_beat/admin.py:197
#, python-brace-format
msgid "{0} task was successfully disabled"
msgid_plural "{0} tasks were successfully disabled"
msgstr[0] "{0} tâche a été désactivée avec succès"
msgstr[1] "{0} tâches ont été désactivées avec succès"
#: django_celery_beat/admin.py:210
msgid "Toggle activity of selected tasks"
msgstr "Bascule l'activité des tâches sélectionnées"
#: django_celery_beat/admin.py:218
#, python-brace-format
msgid "{0} task was successfully toggled"
msgid_plural "{0} tasks were successfully toggled"
msgstr[0] "{0} tâche a été inversée avec succès"
msgstr[1] "{0} tâches ont été inversées avec succès"
#: django_celery_beat/admin.py:225
msgid "Run selected tasks"
msgstr "Démarre les tâches sélectionnées"
#: django_celery_beat/admin.py:246
#, python-brace-format
msgid "task \"{not_found_task_name}\" not found"
msgstr "tâche \"{not_found_task_name}\" introuvable"
#: django_celery_beat/admin.py:262
#, python-brace-format
msgid "{0} task{1} {2} successfully run"
msgstr "{0} tâche{1} {2} a fonctionnée avec succès"
#: django_celery_beat/admin.py:265
msgid "was,were"
msgstr "a été,ont été"
#: django_celery_beat/apps.py:13
msgid "Periodic Tasks"
msgstr "Tâches Périodique"
#: django_celery_beat/models.py:31
msgid "Days"
msgstr "Jours"
#: django_celery_beat/models.py:32
msgid "Hours"
msgstr "Heures"
#: django_celery_beat/models.py:33
msgid "Minutes"
msgstr "Minutes"
#: django_celery_beat/models.py:34
msgid "Seconds"
msgstr "Secondes"
#: django_celery_beat/models.py:35
msgid "Microseconds"
msgstr "Microsecondes"
#: django_celery_beat/models.py:39
msgid "Day"
msgstr "Jour"
#: django_celery_beat/models.py:40
msgid "Hour"
msgstr "Heure"
#: django_celery_beat/models.py:41
msgid "Minute"
msgstr "Minute"
#: django_celery_beat/models.py:42
msgid "Second"
msgstr "Seconde"
#: django_celery_beat/models.py:43
msgid "Microsecond"
msgstr "Microseconde"
#: django_celery_beat/models.py:47
msgid "Astronomical dawn"
msgstr "Aube astronomique"
#: django_celery_beat/models.py:48
msgid "Civil dawn"
msgstr "Aube civile"
#: django_celery_beat/models.py:49
msgid "Nautical dawn"
msgstr "Aube nautique"
#: django_celery_beat/models.py:50
msgid "Astronomical dusk"
msgstr "Crépuscule astronomique"
#: django_celery_beat/models.py:51
msgid "Civil dusk"
msgstr "Crépuscule civil"
#: django_celery_beat/models.py:52
msgid "Nautical dusk"
msgstr "Crépuscule nautique"
#: django_celery_beat/models.py:53
msgid "Solar noon"
msgstr "Midi solaire"
#: django_celery_beat/models.py:54
msgid "Sunrise"
msgstr "Lever du soleil"
#: django_celery_beat/models.py:55
msgid "Sunset"
msgstr "Coucher du soleil"
#: django_celery_beat/models.py:89
msgid "Solar Event"
msgstr "Évènement Solaire"
#: django_celery_beat/models.py:90
msgid "The type of solar event when the job should run"
msgstr "Le type d'évènement solaire pour lequel la tâche devrait démarrer"
#: django_celery_beat/models.py:94
msgid "Latitude"
msgstr "Latitude"
#: django_celery_beat/models.py:95
msgid "Run the task when the event happens at this latitude"
msgstr "Démarre cette tâche lorsque l'évènement se produit à cette latitude"
#: django_celery_beat/models.py:100
msgid "Longitude"
msgstr "Longitude"
#: django_celery_beat/models.py:101
msgid "Run the task when the event happens at this longitude"
msgstr "Démarre cette tâche lorsque cet évènement se produit à cette longitude"
#: django_celery_beat/models.py:108
msgid "solar event"
msgstr "évènement solaire"
#: django_celery_beat/models.py:109
msgid "solar events"
msgstr "évènements solaire"
#: django_celery_beat/models.py:159
msgid "Number of Periods"
msgstr "Nombre de Périodes"
#: django_celery_beat/models.py:160
msgid "Number of interval periods to wait before running the task again"
msgstr ""
"Nombre d'intervale de périodes à attendre avant de démarrer la tâche à "
"nouveau"
#: django_celery_beat/models.py:166
msgid "Interval Period"
msgstr "Période d'Intervale"
#: django_celery_beat/models.py:167
msgid "The type of period between task runs (Example: days)"
msgstr "Le type de période entre chaque démarrage de tâche (Exemple: jours)"
#: django_celery_beat/models.py:173
msgid "interval"
msgstr "intervale"
#: django_celery_beat/models.py:174
msgid "intervals"
msgstr "intervales"
#: django_celery_beat/models.py:201
msgid "every {}"
msgstr "chaque {}"
#: django_celery_beat/models.py:206
msgid "every {} {}"
msgstr "chaque {} {}"
#: django_celery_beat/models.py:217
msgid "Clock Time"
msgstr "Horaire"
#: django_celery_beat/models.py:218
msgid "Run the task at clocked time"
msgstr "Démarre la tâche à l'horaire définie"
#: django_celery_beat/models.py:224 django_celery_beat/models.py:225
msgid "clocked"
msgstr "horaire"
#: django_celery_beat/models.py:265
msgid "Minute(s)"
msgstr "Minute⋅s"
#: django_celery_beat/models.py:267
msgid "Cron Minutes to Run. Use \"*\" for \"all\". (Example: \"0,30\")"
msgstr ""
"Minutes Cron pour démarrer. Utilisez \"*\" pour \"toutes\". (Exemple: "
"\"0,30\")"
#: django_celery_beat/models.py:272
msgid "Hour(s)"
msgstr "Heure⋅s"
#: django_celery_beat/models.py:274
msgid "Cron Hours to Run. Use \"*\" for \"all\". (Example: \"8,20\")"
msgstr ""
"Heures Cron pour démarrer. Utilisez \"*\" pour \"toutes\". (Exemple: "
"\"8,20\")"
#: django_celery_beat/models.py:279
msgid "Day(s) Of The Month"
msgstr "Jour⋅s Du mois"
#: django_celery_beat/models.py:281
msgid ""
"Cron Days Of The Month to Run. Use \"*\" for \"all\". (Example: \"1,15\")"
msgstr ""
"Jours Du mois Cron pour démarrer. Utilisez \"*\" pour \"tous\". (Exemple: "
"\"1,15\")"
#: django_celery_beat/models.py:287
msgid "Month(s) Of The Year"
msgstr "Mois De L'année"
#: django_celery_beat/models.py:289
msgid ""
"Cron Months (1-12) Of The Year to Run. Use \"*\" for \"all\". (Example: "
"\"1,12\")"
msgstr ""
"Mois de l'année pour lesquels Cron doit exécuter. Utilisez \"*\" pour "
"\"tous\". (Exemple : \"1,12\")"
#: django_celery_beat/models.py:295
msgid "Day(s) Of The Week"
msgstr "Jour⋅s de la semaine"
#: django_celery_beat/models.py:297
msgid ""
"Cron Days Of The Week to Run. Use \"*\" for \"all\", Sunday is 0 or 7, "
"Monday is 1. (Example: \"0,5\")"
msgstr ""
"Jours de la semaine pour lesquels Cron doit exécuter. Utilisez \"*\" pour "
"\"tous\", Dimanches est 0 ou 7, Lundi est 1. (Exemple : \"0,5\")"
#: django_celery_beat/models.py:305
msgid "Cron Timezone"
msgstr "Fuseau horaire Cron"
#: django_celery_beat/models.py:307
msgid "Timezone to Run the Cron Schedule on. Default is UTC."
msgstr ""
"Fuseau horaire pour lequel démarrer la planification Cron. UTC par défaut."
#: django_celery_beat/models.py:313
msgid "crontab"
msgstr "crontab"
#: django_celery_beat/models.py:314
msgid "crontabs"
msgstr "crontabs"
#: django_celery_beat/models.py:425
msgid "Name"
msgstr "Nom"
#: django_celery_beat/models.py:426
msgid "Short Description For This Task"
msgstr "Description courte pour cette tâche"
#: django_celery_beat/models.py:431
msgid ""
"The Name of the Celery Task that Should be Run. (Example: \"proj.tasks."
"import_contacts\")"
msgstr ""
"Le nom de la tâche Celery qui devrait être démarrée. (Exemple: \"proj.tasks."
"import_contacts\")"
#: django_celery_beat/models.py:439
msgid "Interval Schedule"
msgstr "Planification intervalée"
#: django_celery_beat/models.py:440
msgid ""
"Interval Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"Planification intervalée pour démarrer cette tâche. Ne mettez qu'un seul "
"type de planification, laissez les autres vides"
#: django_celery_beat/models.py:445
msgid "Crontab Schedule"
msgstr "Planification Crontab"
#: django_celery_beat/models.py:446
msgid ""
"Crontab Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"Planification Crontab pour démarrer cette tâche. Ne mettez qu'un seul type "
"de planification, laissez les autres vides"
#: django_celery_beat/models.py:451
msgid "Solar Schedule"
msgstr "Planification Solaire"
#: django_celery_beat/models.py:452
msgid ""
"Solar Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"Planification Solaire pour démarrer cette tâche. Ne mettez qu'un seul type "
"de planification, laissez les autres vides"
#: django_celery_beat/models.py:457
msgid "Clocked Schedule"
msgstr "Planification Horaire"
#: django_celery_beat/models.py:458
msgid ""
"Clocked Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"Planification Horaire pour démarrer cette tâche. Ne mettez qu'un seul type "
"de planification, laissez les autres vides"
#: django_celery_beat/models.py:464
msgid "Positional Arguments"
msgstr "Arguments Positionnels"
#: django_celery_beat/models.py:466
msgid "JSON encoded positional arguments (Example: [\"arg1\", \"arg2\"])"
msgstr "Arguments positionnels encodés en JSON (Exemple: [\"arg1\", \"arg2\"])"
#: django_celery_beat/models.py:471
msgid "Keyword Arguments"
msgstr "Arguments Nommés"
#: django_celery_beat/models.py:473
msgid "JSON encoded keyword arguments (Example: {\"argument\": \"value\"})"
msgstr "Arguments Nommés encodés en JSON (Exemple: {\"argument\": \"valeur\"})"
#: django_celery_beat/models.py:479
msgid "Queue Override"
msgstr "Surcharge de file d'attente"
#: django_celery_beat/models.py:481
msgid "Queue defined in CELERY_TASK_QUEUES. Leave None for default queuing."
msgstr ""
"File d'attente définie dans CELERY_TASK_QEUEUS. Laissez Vide pour la mise en "
"file d'attente par défaut."
#: django_celery_beat/models.py:490
msgid "Exchange"
msgstr "Échange"
#: django_celery_beat/models.py:491
msgid "Override Exchange for low-level AMQP routing"
msgstr "Surcharge d'échange pour un routage AMQP bas-niveau"
#: django_celery_beat/models.py:495
msgid "Routing Key"
msgstr "Clé de routage"
#: django_celery_beat/models.py:496
msgid "Override Routing Key for low-level AMQP routing"
msgstr "Surcharge de clé de routage pour un routage AMQP bas-niveau"
#: django_celery_beat/models.py:500
msgid "AMQP Message Headers"
msgstr "Message d'en-têtes AMQP"
#: django_celery_beat/models.py:501
msgid "JSON encoded message headers for the AMQP message."
msgstr "Message d'en-têtes encodés en JSON pour le message AMQP"
#: django_celery_beat/models.py:507
msgid "Priority"
msgstr "Priorité"
#: django_celery_beat/models.py:509
msgid ""
"Priority Number between 0 and 255. Supported by: RabbitMQ, Redis (priority "
"reversed, 0 is highest)."
msgstr ""
"Valeur de priorité entre 0 et 255. Supporté par: RabbitMQ, Redis (priorité "
"inversé, 0 est plus élevé)."
#: django_celery_beat/models.py:514
msgid "Expires Datetime"
msgstr "Date et heure d'expiration"
#: django_celery_beat/models.py:516
msgid ""
"Datetime after which the schedule will no longer trigger the task to run"
msgstr ""
"Date et heure après laquelle la planification ne déclenchera plus la tâche à "
"démarrer"
#: django_celery_beat/models.py:521
msgid "Expires timedelta with seconds"
msgstr "Différence de temps en secondes d'expiration"
#: django_celery_beat/models.py:523
msgid ""
"Timedelta with seconds which the schedule will no longer trigger the task to "
"run"
msgstr ""
"Différence de temps en secondes à laquelle la planification ne déclenchera "
"plus la tâche à démarrer"
#: django_celery_beat/models.py:529
msgid "One-off Task"
msgstr "Tâche Ponctuelle"
#: django_celery_beat/models.py:531
msgid "If True, the schedule will only run the task a single time"
msgstr "Si Vrai, la planification ne démarrera la tâche qu'une seule fois"
#: django_celery_beat/models.py:535
msgid "Start Datetime"
msgstr "Date et heure de démarrage"
#: django_celery_beat/models.py:537
msgid "Datetime when the schedule should begin triggering the task to run"
msgstr ""
"Date et heure à laquelle la planification devrait commencer à déclencher la "
"tâche à démarrer"
#: django_celery_beat/models.py:542
msgid "Enabled"
msgstr "Activé"
#: django_celery_beat/models.py:543
msgid "Set to False to disable the schedule"
msgstr "Mettre à Faux pour désactiver la planification"
#: django_celery_beat/models.py:548
msgid "Last Run Datetime"
msgstr "Date et heure du dernier démarrage"
#: django_celery_beat/models.py:550
msgid ""
"Datetime that the schedule last triggered the task to run. Reset to None if "
"enabled is set to False."
msgstr ""
"Date et heure à laquelle la planification à dernièrement déclenchée la tâche "
"à démarrer. Est remis à Vide si activé est mis à Faux"
#: django_celery_beat/models.py:555
msgid "Total Run Count"
msgstr "Nombre total de démarrages"
#: django_celery_beat/models.py:557
msgid "Running count of how many times the schedule has triggered the task"
msgstr "Compte combien de fois la planification a déclenchée la tâche"
#: django_celery_beat/models.py:562
msgid "Last Modified"
msgstr "Dernière modification"
#: django_celery_beat/models.py:563
msgid "Datetime that this PeriodicTask was last modified"
msgstr "Date et heure de la dernière modification de cette Tâche Périodique"
#: django_celery_beat/models.py:567
msgid "Description"
msgstr "Description"
#: django_celery_beat/models.py:569
msgid "Detailed description about the details of this Periodic Task"
msgstr "Description détaillée à propos des détails de cette Tâche Périodique"
#: django_celery_beat/models.py:578
msgid "periodic task"
msgstr "tâche périodique"
#: django_celery_beat/models.py:579
msgid "periodic tasks"
msgstr "tâches périodique"
#: django_celery_beat/templates/admin/djcelery/change_list.html:6
msgid "Home"
msgstr "Accueil"

View File

@@ -0,0 +1,528 @@
# Korean translation strings for django-celery-beat
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <jay.jaeyoung@gmail.com>, 2022.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-12-22 19:03+0000\n"
"PO-Revision-Date: 2022-10-14 23:48+0200\n"
"Last-Translator: Jaeyoung Heo <jay.jaeyoung@gmail.com>\n"
"Language-Team: \n"
"Language: ko\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: django_celery_beat/admin.py:60
msgid "Task (registered)"
msgstr "등록 태스크 목록"
#: django_celery_beat/admin.py:64
msgid "Task (custom)"
msgstr "사용자 정의 태스크"
#: django_celery_beat/admin.py:81
msgid "Need name of task"
msgstr "태스크 이름이 필요 합니다."
#: django_celery_beat/admin.py:87 django_celery_beat/models.py:605
msgid "Only one can be set, in expires and expire_seconds"
msgstr "'만료 시각'과 '만료 기준 초' 중에 하나만 지정할 수 있습니다."
#: django_celery_beat/admin.py:97
#, python-format
msgid "Unable to parse JSON: %s"
msgstr "해석할 수 없습니다. JSON: %s"
#: django_celery_beat/admin.py:125
#, fuzzy
#| msgid "Solar Schedule"
msgid "Schedule"
msgstr "Solar Schedule"
#: django_celery_beat/admin.py:130
#, fuzzy
#| msgid "Keyword Arguments"
msgid "Arguments"
msgstr "Keyword Arguments"
#: django_celery_beat/admin.py:134
msgid "Execution Options"
msgstr ""
#: django_celery_beat/admin.py:177
#, python-brace-format
msgid "{0} task{1} {2} successfully {3}"
msgstr "{0} 태스크{1} {2} 성공적으로 {3}"
#: django_celery_beat/admin.py:180 django_celery_beat/admin.py:247
msgid "was,were"
msgstr "가,들이"
#: django_celery_beat/admin.py:189
msgid "Enable selected tasks"
msgstr "선택된 태스크들을 활성화 합니다."
#: django_celery_beat/admin.py:195
msgid "Disable selected tasks"
msgstr "선택된 태스크들을 비활성화 합니다."
#: django_celery_beat/admin.py:207
msgid "Toggle activity of selected tasks"
msgstr "선택된 태스크들의 활성화 상태를 토글 합니다."
#: django_celery_beat/admin.py:228
#, fuzzy, python-brace-format
#| msgid "task \"{0}\" not found"
msgid "task \"{not_found_task_name}\" not found"
msgstr "태스크 \"{0}\" 을 찾을 수 없습니다."
#: django_celery_beat/admin.py:244
#, python-brace-format
msgid "{0} task{1} {2} successfully run"
msgstr "{0} 태스크{1} {2} 성공적으로 작동했습니다."
#: django_celery_beat/admin.py:250
msgid "Run selected tasks"
msgstr "선택된 태스크들을 실행 합니다."
#: django_celery_beat/apps.py:13
msgid "Periodic Tasks"
msgstr "주기적인 태스크들"
#: django_celery_beat/models.py:30
msgid "Days"
msgstr "일"
#: django_celery_beat/models.py:31
msgid "Hours"
msgstr "시간"
#: django_celery_beat/models.py:32
msgid "Minutes"
msgstr "분"
#: django_celery_beat/models.py:33
msgid "Seconds"
msgstr "초"
#: django_celery_beat/models.py:34
msgid "Microseconds"
msgstr "마이크로초"
#: django_celery_beat/models.py:38
msgid "Day"
msgstr "일"
#: django_celery_beat/models.py:39
msgid "Hour"
msgstr "시"
#: django_celery_beat/models.py:40
msgid "Minute"
msgstr "분"
#: django_celery_beat/models.py:41
msgid "Second"
msgstr "초"
#: django_celery_beat/models.py:42
msgid "Microsecond"
msgstr "마이크로초"
#: django_celery_beat/models.py:46
msgid "Astronomical dawn"
msgstr "천문 박명"
#: django_celery_beat/models.py:47
msgid "Civil dawn"
msgstr "시민 박명"
#: django_celery_beat/models.py:48
msgid "Nautical dawn"
msgstr "항해 박명"
#: django_celery_beat/models.py:49
msgid "Astronomical dusk"
msgstr "천문 황혼"
#: django_celery_beat/models.py:50
msgid "Civil dusk"
msgstr "시민 황혼"
#: django_celery_beat/models.py:51
msgid "Nautical dusk"
msgstr "항해 황혼"
#: django_celery_beat/models.py:52
msgid "Solar noon"
msgstr "정오"
#: django_celery_beat/models.py:53
msgid "Sunrise"
msgstr "일출"
#: django_celery_beat/models.py:54
msgid "Sunset"
msgstr "일몰"
#: django_celery_beat/models.py:88
msgid "Solar Event"
msgstr "Solar Event"
#: django_celery_beat/models.py:89
msgid "The type of solar event when the job should run"
msgstr "태스크가 작동 해야 하는 Solar Event"
#: django_celery_beat/models.py:93
msgid "Latitude"
msgstr "위도"
#: django_celery_beat/models.py:94
msgid "Run the task when the event happens at this latitude"
msgstr "입력된 위도에서 Solar Event 가 발생하면 태스크를 실행합니다."
#: django_celery_beat/models.py:99
msgid "Longitude"
msgstr "경도"
#: django_celery_beat/models.py:100
msgid "Run the task when the event happens at this longitude"
msgstr "입력된 경도에서 Solar Event 가 발생하면 태스크를 실행합니다."
#: django_celery_beat/models.py:107
msgid "solar event"
msgstr "solar event"
#: django_celery_beat/models.py:108
msgid "solar events"
msgstr "solar events"
#: django_celery_beat/models.py:158
msgid "Number of Periods"
msgstr "매"
#: django_celery_beat/models.py:159
msgid "Number of interval periods to wait before running the task again"
msgstr "태스크의 다음 동작까지 몇 번의 간격을 기다릴 것인지 입력합니다."
#: django_celery_beat/models.py:165
msgid "Interval Period"
msgstr "간격"
#: django_celery_beat/models.py:166
msgid "The type of period between task runs (Example: days)"
msgstr "실행 간격 (예: 일, 시간)"
#: django_celery_beat/models.py:172
msgid "interval"
msgstr "interval"
#: django_celery_beat/models.py:173
msgid "intervals"
msgstr "intervals"
#: django_celery_beat/models.py:200
msgid "every {}"
msgstr "매 {}"
#: django_celery_beat/models.py:205
msgid "every {} {}"
msgstr "매 {} {}"
#: django_celery_beat/models.py:216
msgid "Clock Time"
msgstr "Clock Time"
#: django_celery_beat/models.py:217
msgid "Run the task at clocked time"
msgstr "Clock Time 기준으로 태스크를 작동합니다."
#: django_celery_beat/models.py:223 django_celery_beat/models.py:224
msgid "clocked"
msgstr "clocked"
#: django_celery_beat/models.py:264
msgid "Minute(s)"
msgstr "분"
#: django_celery_beat/models.py:266
msgid "Cron Minutes to Run. Use \"*\" for \"all\". (Example: \"0,30\")"
msgstr "Cron 의 분. 모두인 경우 \"*\". (예: \"0,30\")"
#: django_celery_beat/models.py:271
msgid "Hour(s)"
msgstr "시"
#: django_celery_beat/models.py:273
msgid "Cron Hours to Run. Use \"*\" for \"all\". (Example: \"8,20\")"
msgstr "Cron 의 시간. 모두인 경우 \"*\". (예: \"8,20\")"
#: django_celery_beat/models.py:278
msgid "Day(s) Of The Week"
msgstr "요일"
#: django_celery_beat/models.py:280
#, fuzzy
#| msgid ""
#| "Cron Days Of The Week to Run. Use \"*\" for \"all\". (Example: \"0,5\")"
msgid ""
"Cron Days Of The Week to Run. Use \"*\" for \"all\", Sunday is 0 or 7, "
"Monday is 1. (Example: \"0,5\")"
msgstr "Cron 의 요일. 모두인 경우 \"*\". (예: \"0,5\")"
#: django_celery_beat/models.py:286
msgid "Day(s) Of The Month"
msgstr "일"
#: django_celery_beat/models.py:288
msgid ""
"Cron Days Of The Month to Run. Use \"*\" for \"all\". (Example: \"1,15\")"
msgstr "Cron 의 일. 모두인 경우 \"*\". (예: \"1,15\")"
#: django_celery_beat/models.py:294
msgid "Month(s) Of The Year"
msgstr "월"
#: django_celery_beat/models.py:296
#, fuzzy
#| msgid ""
#| "Cron Months Of The Year to Run. Use \"*\" for \"all\". (Example: \"0,6\")"
msgid ""
"Cron Months (1-12) Of The Year to Run. Use \"*\" for \"all\". (Example: "
"\"1,12\")"
msgstr "Cron 의 월. 모두인 경우 \"*\"."
#: django_celery_beat/models.py:304
msgid "Cron Timezone"
msgstr "타임존"
#: django_celery_beat/models.py:306
msgid "Timezone to Run the Cron Schedule on. Default is UTC."
msgstr "Cron 의 타임존. 기본값은 UTC"
#: django_celery_beat/models.py:312
msgid "crontab"
msgstr "crontab"
#: django_celery_beat/models.py:313
msgid "crontabs"
msgstr "crontabs"
#: django_celery_beat/models.py:404
msgid "Name"
msgstr "태스크 이름"
#: django_celery_beat/models.py:405
msgid "Short Description For This Task"
msgstr "태스크의 간단한 설명을 작성합니다."
#: django_celery_beat/models.py:410
msgid ""
"The Name of the Celery Task that Should be Run. (Example: \"proj.tasks."
"import_contacts\")"
msgstr ""
"실행 되어야 하는 셀러리 태스크의 이름 (예: \"proj.tasks.import_contacts\")"
#: django_celery_beat/models.py:418
msgid "Interval Schedule"
msgstr "Interval Schedule"
#: django_celery_beat/models.py:419
msgid ""
"Interval Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"태스크 실행 Interval Schedule. 한 종류의 스케줄 타입을 지정하면 나머지는 빈 "
"값으로 두어야 합니다."
#: django_celery_beat/models.py:424
msgid "Crontab Schedule"
msgstr "Crontab Schedule"
#: django_celery_beat/models.py:425
msgid ""
"Crontab Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"태스크 실행 Crontab Schedule. 한 종류의 스케줄 타입을 지정하면 나머지는 빈 값"
"으로 두어야 합니다."
#: django_celery_beat/models.py:430
msgid "Solar Schedule"
msgstr "Solar Schedule"
#: django_celery_beat/models.py:431
msgid ""
"Solar Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"태스크 실행을 위한 Solar Schedule. 한 종류의 스케줄 타입을 지정하면 나머지는 "
"빈 값으로 두어야 합니다."
#: django_celery_beat/models.py:436
msgid "Clocked Schedule"
msgstr "Clocked Schedule"
#: django_celery_beat/models.py:437
msgid ""
"Clocked Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"태스크 실행을 위한 Clocked Schedule. 한 종류의 스케줄 타입을 지정하면 나머지"
"는 빈 값으로 두어야 합니다."
#: django_celery_beat/models.py:443
msgid "Positional Arguments"
msgstr "Positional Arguments"
#: django_celery_beat/models.py:445
msgid "JSON encoded positional arguments (Example: [\"arg1\", \"arg2\"])"
msgstr "JSON 형태로 인코딩된 위치 인자 (예: [\"arg1\", \"arg2\"])"
#: django_celery_beat/models.py:450
msgid "Keyword Arguments"
msgstr "Keyword Arguments"
#: django_celery_beat/models.py:452
msgid "JSON encoded keyword arguments (Example: {\"argument\": \"value\"})"
msgstr "JSON 형태로 인코딩된 키워드 인자 (예: {\"argument\": \"value\"})"
#: django_celery_beat/models.py:458
msgid "Queue Override"
msgstr "Queue Override"
#: django_celery_beat/models.py:460
msgid "Queue defined in CELERY_TASK_QUEUES. Leave None for default queuing."
msgstr "CELERY_TASK_QUEES 에 정의된 큐, 빈 값으로 두면 기본 큐를 사용합니다."
#: django_celery_beat/models.py:469
msgid "Exchange"
msgstr "Exchange"
#: django_celery_beat/models.py:470
msgid "Override Exchange for low-level AMQP routing"
msgstr "low-level AMQP 를 원하는 경우 Exchange 를 오버라이드 합니다."
#: django_celery_beat/models.py:474
msgid "Routing Key"
msgstr "Routing Key"
#: django_celery_beat/models.py:475
msgid "Override Routing Key for low-level AMQP routing"
msgstr "low-level AMQP 를 원하는 경우 Routing Key 를 오버라이드 합니다."
#: django_celery_beat/models.py:479
msgid "AMQP Message Headers"
msgstr "AMQP 메시지 헤더"
#: django_celery_beat/models.py:480
msgid "JSON encoded message headers for the AMQP message."
msgstr "AMQP 메시지를 위해 JSON 형식으로 인코딩 된 메시지 헤더"
#: django_celery_beat/models.py:486
msgid "Priority"
msgstr "Priority"
#: django_celery_beat/models.py:488
msgid ""
"Priority Number between 0 and 255. Supported by: RabbitMQ, Redis (priority "
"reversed, 0 is highest)."
msgstr ""
"0과 255사이의 우선 순위 숫자. RabbitMQ, Redis 에서 지원합니다. (0이 높은 우선"
"순위를 가집니다.)"
#: django_celery_beat/models.py:493
msgid "Expires Datetime"
msgstr "만료 일시"
#: django_celery_beat/models.py:495
msgid ""
"Datetime after which the schedule will no longer trigger the task to run"
msgstr "만료 일시 이후에는 태스크가 작동하지 않습니다."
#: django_celery_beat/models.py:500
msgid "Expires timedelta with seconds"
msgstr "초 단위 만료 시간"
#: django_celery_beat/models.py:502
msgid ""
"Timedelta with seconds which the schedule will no longer trigger the task to "
"run"
msgstr "입력된 만료 초가 지난 뒤에는 태스크가 작동하지 않습니다."
#: django_celery_beat/models.py:508
msgid "One-off Task"
msgstr "One-off 태스크"
#: django_celery_beat/models.py:510
msgid "If True, the schedule will only run the task a single time"
msgstr "체크된 경우, 태스크는 한 번만 실행 됩니다."
#: django_celery_beat/models.py:514
msgid "Start Datetime"
msgstr "시작 일시"
#: django_celery_beat/models.py:516
msgid "Datetime when the schedule should begin triggering the task to run"
msgstr "태스크 스케줄의 작동 시작 일시"
#: django_celery_beat/models.py:521
msgid "Enabled"
msgstr "활성화 여부"
#: django_celery_beat/models.py:522
msgid "Set to False to disable the schedule"
msgstr "체크를 해제하면 비활성화가 됩니다."
#: django_celery_beat/models.py:527
msgid "Last Run Datetime"
msgstr "최종 작동 일시"
#: django_celery_beat/models.py:529
msgid ""
"Datetime that the schedule last triggered the task to run. Reset to None if "
"enabled is set to False."
msgstr ""
"태스크가 최종적으로 작동한 시간. 만약 테스크가 비활성화 된 경우 None 으로 지"
"정됩니다."
#: django_celery_beat/models.py:534
msgid "Total Run Count"
msgstr "실행 횟수"
#: django_celery_beat/models.py:536
msgid "Running count of how many times the schedule has triggered the task"
msgstr "태스크의 실행 횟수"
#: django_celery_beat/models.py:541
msgid "Last Modified"
msgstr "최종 변경 일시"
#: django_celery_beat/models.py:542
msgid "Datetime that this PeriodicTask was last modified"
msgstr "태스크가 최종적으로 변경된 일시"
#: django_celery_beat/models.py:546
msgid "Description"
msgstr "설명"
#: django_celery_beat/models.py:548
msgid "Detailed description about the details of this Periodic Task"
msgstr "태스크에 대한 상세 설명을 작성합니다."
#: django_celery_beat/models.py:557
msgid "periodic task"
msgstr "periodic task"
#: django_celery_beat/models.py:558
msgid "periodic tasks"
msgstr "periodic tasks"
#: django_celery_beat/templates/admin/djcelery/change_list.html:6
msgid "Home"
msgstr "Home"

View File

@@ -0,0 +1,538 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: 1.5.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-12-22 19:03+0000\n"
"PO-Revision-Date: 2022-10-14 23:48+0200\n"
"Last-Translator: Daniil Kharkov <fadeddexofan@gmail.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || "
"(n%100>=11 && n%100<=14)? 2 : 3);\n"
#: django_celery_beat/admin.py:60
msgid "Task (registered)"
msgstr "Задача (зарегистрированные)"
#: django_celery_beat/admin.py:64
msgid "Task (custom)"
msgstr "Задача (пользовательская)"
#: django_celery_beat/admin.py:81
msgid "Need name of task"
msgstr "Укажите название задачи"
#: django_celery_beat/admin.py:87 django_celery_beat/models.py:605
msgid "Only one can be set, in expires and expire_seconds"
msgstr ""
#: django_celery_beat/admin.py:97
#, python-format
msgid "Unable to parse JSON: %s"
msgstr "Невозможно проанализировать JSON: %s"
#: django_celery_beat/admin.py:125
#, fuzzy
#| msgid "Solar Schedule"
msgid "Schedule"
msgstr "Астрономическое"
#: django_celery_beat/admin.py:130
#, fuzzy
#| msgid "Keyword Arguments"
msgid "Arguments"
msgstr "Именованные аргументы"
#: django_celery_beat/admin.py:134
msgid "Execution Options"
msgstr ""
#: django_celery_beat/admin.py:177
#, python-brace-format
msgid "{0} task{1} {2} successfully {3}"
msgstr "{0} задача {1} {2} успешно {3}"
#: django_celery_beat/admin.py:180 django_celery_beat/admin.py:247
msgid "was,were"
msgstr "был, были"
#: django_celery_beat/admin.py:189
msgid "Enable selected tasks"
msgstr "Включить выбранные задачи"
#: django_celery_beat/admin.py:195
msgid "Disable selected tasks"
msgstr "Выключить выбранные задачи"
#: django_celery_beat/admin.py:207
msgid "Toggle activity of selected tasks"
msgstr "Переключить активность выбранных задач"
#: django_celery_beat/admin.py:228
#, fuzzy, python-brace-format
#| msgid "task \"{0}\" not found"
msgid "task \"{not_found_task_name}\" not found"
msgstr "задача \"{0}\" не найдена"
#: django_celery_beat/admin.py:244
#, python-brace-format
msgid "{0} task{1} {2} successfully run"
msgstr "{0} задача{1} {2} успешно выполнена"
#: django_celery_beat/admin.py:250
msgid "Run selected tasks"
msgstr "Запустить выбранные задачи"
#: django_celery_beat/apps.py:13
msgid "Periodic Tasks"
msgstr "Периодические Задачи"
#: django_celery_beat/models.py:30
msgid "Days"
msgstr "Дни"
#: django_celery_beat/models.py:31
msgid "Hours"
msgstr "Часы"
#: django_celery_beat/models.py:32
msgid "Minutes"
msgstr "Минуты"
#: django_celery_beat/models.py:33
msgid "Seconds"
msgstr "Секунды"
#: django_celery_beat/models.py:34
msgid "Microseconds"
msgstr "Микросекунды"
#: django_celery_beat/models.py:38
msgid "Day"
msgstr "день"
#: django_celery_beat/models.py:39
msgid "Hour"
msgstr "время"
#: django_celery_beat/models.py:40
msgid "Minute"
msgstr "минут"
#: django_celery_beat/models.py:41
msgid "Second"
msgstr "Секунды"
#: django_celery_beat/models.py:42
msgid "Microsecond"
msgstr "Микросекунды"
#: django_celery_beat/models.py:46
msgid "Astronomical dawn"
msgstr ""
#: django_celery_beat/models.py:47
msgid "Civil dawn"
msgstr ""
#: django_celery_beat/models.py:48
msgid "Nautical dawn"
msgstr ""
#: django_celery_beat/models.py:49
msgid "Astronomical dusk"
msgstr ""
#: django_celery_beat/models.py:50
msgid "Civil dusk"
msgstr ""
#: django_celery_beat/models.py:51
msgid "Nautical dusk"
msgstr ""
#: django_celery_beat/models.py:52
#, fuzzy
#| msgid "Solar Event"
msgid "Solar noon"
msgstr "Астрономическое"
#: django_celery_beat/models.py:53
msgid "Sunrise"
msgstr ""
#: django_celery_beat/models.py:54
msgid "Sunset"
msgstr ""
#: django_celery_beat/models.py:88
msgid "Solar Event"
msgstr "Астрономическое"
#: django_celery_beat/models.py:89
msgid "The type of solar event when the job should run"
msgstr "Тип астрономического события для запуска задачи"
#: django_celery_beat/models.py:93
msgid "Latitude"
msgstr "Широта"
#: django_celery_beat/models.py:94
msgid "Run the task when the event happens at this latitude"
msgstr "Запуск задачи, когда событие происходит на данной широте"
#: django_celery_beat/models.py:99
msgid "Longitude"
msgstr "Долгота"
#: django_celery_beat/models.py:100
msgid "Run the task when the event happens at this longitude"
msgstr "Запуск задачи, когда событие происходит на данной долготе"
#: django_celery_beat/models.py:107
msgid "solar event"
msgstr "астрономическое событие"
#: django_celery_beat/models.py:108
msgid "solar events"
msgstr "астрономические события"
#: django_celery_beat/models.py:158
msgid "Number of Periods"
msgstr "Число периодов"
#: django_celery_beat/models.py:159
msgid "Number of interval periods to wait before running the task again"
msgstr "Количество периодов интервала перед новым запуском задачи"
#: django_celery_beat/models.py:165
msgid "Interval Period"
msgstr "Интервальный период"
#: django_celery_beat/models.py:166
msgid "The type of period between task runs (Example: days)"
msgstr "Тип периода между запусками задачи (Например: дни)"
#: django_celery_beat/models.py:172
msgid "interval"
msgstr "интервал"
#: django_celery_beat/models.py:173
msgid "intervals"
msgstr "интервалы"
#: django_celery_beat/models.py:200
msgid "every {}"
msgstr "каждые {}"
#: django_celery_beat/models.py:205
msgid "every {} {}"
msgstr "каждые {} {}"
#: django_celery_beat/models.py:216
msgid "Clock Time"
msgstr "Время"
#: django_celery_beat/models.py:217
msgid "Run the task at clocked time"
msgstr "Запуск задачи в указанное время"
#: django_celery_beat/models.py:223 django_celery_beat/models.py:224
msgid "clocked"
msgstr "время"
#: django_celery_beat/models.py:264
msgid "Minute(s)"
msgstr "Минуты"
#: django_celery_beat/models.py:266
msgid "Cron Minutes to Run. Use \"*\" for \"all\". (Example: \"0,30\")"
msgstr "Cron минуты. Используйте \"*\" для \"каждую\". (Например: \"0,30\")"
#: django_celery_beat/models.py:271
msgid "Hour(s)"
msgstr "Часы"
#: django_celery_beat/models.py:273
msgid "Cron Hours to Run. Use \"*\" for \"all\". (Example: \"8,20\")"
msgstr "Cron часы. Используйте \"*\" для \"каждый\". (Например: \"8,20\")"
#: django_celery_beat/models.py:278
msgid "Day(s) Of The Week"
msgstr "Дни недели"
#: django_celery_beat/models.py:280
#, fuzzy
#| msgid ""
#| "Cron Days Of The Week to Run. Use \"*\" for \"all\". (Example: \"0,5\")"
msgid ""
"Cron Days Of The Week to Run. Use \"*\" for \"all\", Sunday is 0 or 7, "
"Monday is 1. (Example: \"0,5\")"
msgstr "Cron дни недели. Используйте \"*\" для \"каждый\". (Например: \"0,5\")"
#: django_celery_beat/models.py:286
msgid "Day(s) Of The Month"
msgstr "Дни"
#: django_celery_beat/models.py:288
msgid ""
"Cron Days Of The Month to Run. Use \"*\" for \"all\". (Example: \"1,15\")"
msgstr "Cron дни. Используйте \"*\" для \"каждый\". (Например: \"1,15\")"
#: django_celery_beat/models.py:294
msgid "Month(s) Of The Year"
msgstr "Месяцы"
#: django_celery_beat/models.py:296
#, fuzzy
#| msgid ""
#| "Cron Months Of The Year to Run. Use \"*\" for \"all\". (Example: \"0,6\")"
msgid ""
"Cron Months (1-12) Of The Year to Run. Use \"*\" for \"all\". (Example: "
"\"1,12\")"
msgstr "Cron месяцы. Используйте \"*\" для \"каждый\". (Например: \"0,6\")"
#: django_celery_beat/models.py:304
msgid "Cron Timezone"
msgstr "Временная зона для Cron"
#: django_celery_beat/models.py:306
msgid "Timezone to Run the Cron Schedule on. Default is UTC."
msgstr "Временная зона для Cron расписания. UTC по умолчанию."
#: django_celery_beat/models.py:312
msgid "crontab"
msgstr "crontab"
#: django_celery_beat/models.py:313
msgid "crontabs"
msgstr "crontab"
#: django_celery_beat/models.py:404
msgid "Name"
msgstr "Название"
#: django_celery_beat/models.py:405
msgid "Short Description For This Task"
msgstr "Краткое описание для этой задачи"
#: django_celery_beat/models.py:410
msgid ""
"The Name of the Celery Task that Should be Run. (Example: \"proj.tasks."
"import_contacts\")"
msgstr ""
"Имя запускаемой Celery задачи. (Например: \"proj.tasks.import_contacts\")"
#: django_celery_beat/models.py:418
msgid "Interval Schedule"
msgstr "Интервал"
#: django_celery_beat/models.py:419
msgid ""
"Interval Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"Интервальное расписание для запуска задачи. Выберите только один тип "
"расписания, остальные оставьте пустыми."
#: django_celery_beat/models.py:424
msgid "Crontab Schedule"
msgstr "Crontab"
#: django_celery_beat/models.py:425
msgid ""
"Crontab Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"Crontab расписание для запуска задачи. Выберите только один тип расписания, "
"остальные оставьте пустыми."
#: django_celery_beat/models.py:430
msgid "Solar Schedule"
msgstr "Астрономическое"
#: django_celery_beat/models.py:431
msgid ""
"Solar Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"Астрономическое расписание для запуска задачи. Выберите только один тип "
"расписания, остальные оставьте пустыми."
#: django_celery_beat/models.py:436
msgid "Clocked Schedule"
msgstr "Хронометрическое"
#: django_celery_beat/models.py:437
msgid ""
"Clocked Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr ""
"Хронометрическое расписание для запуска задачи. Выберите только один тип "
"расписания, остальные оставьте пустыми."
#: django_celery_beat/models.py:443
msgid "Positional Arguments"
msgstr "Позиционные аргументы"
#: django_celery_beat/models.py:445
msgid "JSON encoded positional arguments (Example: [\"arg1\", \"arg2\"])"
msgstr ""
"Закодированные в JSON позиционные аргументы (Например: [\"arg1\", \"arg2\"])"
#: django_celery_beat/models.py:450
msgid "Keyword Arguments"
msgstr "Именованные аргументы"
#: django_celery_beat/models.py:452
msgid "JSON encoded keyword arguments (Example: {\"argument\": \"value\"})"
msgstr ""
"Закодированные в JSON именованные аргументы (Например: {\"argument\": "
"\"value\"})"
#: django_celery_beat/models.py:458
msgid "Queue Override"
msgstr "Переопределение очереди"
#: django_celery_beat/models.py:460
msgid "Queue defined in CELERY_TASK_QUEUES. Leave None for default queuing."
msgstr ""
"Очередь задана в CELERY_TASK_QUEUES. Оставьте None для стандартного "
"распределения."
#: django_celery_beat/models.py:469
msgid "Exchange"
msgstr "Exchange"
#: django_celery_beat/models.py:470
msgid "Override Exchange for low-level AMQP routing"
msgstr "Override Exchange for low-level AMQP routing"
#: django_celery_beat/models.py:474
msgid "Routing Key"
msgstr "Ключ маршрутизации"
#: django_celery_beat/models.py:475
msgid "Override Routing Key for low-level AMQP routing"
msgstr "Override Routing Key for low-level AMQP routing"
#: django_celery_beat/models.py:479
msgid "AMQP Message Headers"
msgstr "Заголовки сообщения AMQP"
#: django_celery_beat/models.py:480
msgid "JSON encoded message headers for the AMQP message."
msgstr "Закодированные в JSON заголовки для AMQP сообщения."
#: django_celery_beat/models.py:486
msgid "Priority"
msgstr "Приоритет"
#: django_celery_beat/models.py:488
msgid ""
"Priority Number between 0 and 255. Supported by: RabbitMQ, Redis (priority "
"reversed, 0 is highest)."
msgstr ""
"Число между 0 и 255. Поддерживается в: RabbitMQ, Redis (приоритет по "
"убыванию, 0 наивысший)."
#: django_celery_beat/models.py:493
msgid "Expires Datetime"
msgstr "Истекает"
#: django_celery_beat/models.py:495
msgid ""
"Datetime after which the schedule will no longer trigger the task to run"
msgstr "Время, после которого расписание больше не будет запускать задачу"
#: django_celery_beat/models.py:500
msgid "Expires timedelta with seconds"
msgstr ""
#: django_celery_beat/models.py:502
#, fuzzy
#| msgid ""
#| "Datetime after which the schedule will no longer trigger the task to run"
msgid ""
"Timedelta with seconds which the schedule will no longer trigger the task to "
"run"
msgstr "Время, после которого расписание больше не будет запускать задачу"
#: django_celery_beat/models.py:508
msgid "One-off Task"
msgstr "Одноразовая задача"
#: django_celery_beat/models.py:510
msgid "If True, the schedule will only run the task a single time"
msgstr "Если включено, то задача будет запущена только один раз"
#: django_celery_beat/models.py:514
msgid "Start Datetime"
msgstr "Время начала"
#: django_celery_beat/models.py:516
msgid "Datetime when the schedule should begin triggering the task to run"
msgstr "Время начала вызовов задачи расписанием"
#: django_celery_beat/models.py:521
msgid "Enabled"
msgstr "Активна"
#: django_celery_beat/models.py:522
msgid "Set to False to disable the schedule"
msgstr "Выключите для отключения расписания"
#: django_celery_beat/models.py:527
msgid "Last Run Datetime"
msgstr "Последний запуск"
#: django_celery_beat/models.py:529
msgid ""
"Datetime that the schedule last triggered the task to run. Reset to None if "
"enabled is set to False."
msgstr "Время последнего вызова задачи. None если задача выключена."
#: django_celery_beat/models.py:534
msgid "Total Run Count"
msgstr "Запусков всего"
#: django_celery_beat/models.py:536
msgid "Running count of how many times the schedule has triggered the task"
msgstr "Количество запусков задачи этим расписанием"
#: django_celery_beat/models.py:541
msgid "Last Modified"
msgstr "Последнее изменение"
#: django_celery_beat/models.py:542
msgid "Datetime that this PeriodicTask was last modified"
msgstr "Время последнего изменения этой задачи"
#: django_celery_beat/models.py:546
msgid "Description"
msgstr "Описание"
#: django_celery_beat/models.py:548
msgid "Detailed description about the details of this Periodic Task"
msgstr "Подробное описание того, что делает эта задача"
#: django_celery_beat/models.py:557
msgid "periodic task"
msgstr "периодическая задача"
#: django_celery_beat/models.py:558
msgid "periodic tasks"
msgstr "периодические задачи"
#: django_celery_beat/templates/admin/djcelery/change_list.html:6
msgid "Home"
msgstr ""

View File

@@ -0,0 +1,524 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-01-25 16:58+0800\n"
"PO-Revision-Date: 2022-10-14 23:48+0200\n"
"Last-Translator: Rainshaw <rxg@live.com>\n"
"Language-Team: x_zhuo <LL@li.org>\n"
"Language: zh-Hans \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: django_celery_beat/admin.py:60
msgid "Task (registered)"
msgstr "任务 (已注册的)"
#: django_celery_beat/admin.py:64
msgid "Task (custom)"
msgstr "任务 (自定义)"
#: django_celery_beat/admin.py:81
msgid "Need name of task"
msgstr "任务需要一个名称"
#: django_celery_beat/admin.py:87 django_celery_beat/models.py:618
msgid "Only one can be set, in expires and expire_seconds"
msgstr "不可以同时设置 expires 和 expire_seconds 字段"
#: django_celery_beat/admin.py:97
#, python-format
msgid "Unable to parse JSON: %s"
msgstr "无法解析 JSON: %s"
#: django_celery_beat/admin.py:125
#, fuzzy
#| msgid "Solar Schedule"
msgid "Schedule"
msgstr "日程时间表"
#: django_celery_beat/admin.py:130
#, fuzzy
#| msgid "Keyword Arguments"
msgid "Arguments"
msgstr "关键字参数"
#: django_celery_beat/admin.py:134
msgid "Execution Options"
msgstr ""
#: django_celery_beat/admin.py:179
#, python-brace-format
msgid "{0} task{1} {2} successfully {3}"
msgstr "{0} 任务{1} {2} 成功 {3}"
#: django_celery_beat/admin.py:182 django_celery_beat/admin.py:249
msgid "was,were"
msgstr "将"
#: django_celery_beat/admin.py:191
msgid "Enable selected tasks"
msgstr "启用选中的任务"
#: django_celery_beat/admin.py:197
msgid "Disable selected tasks"
msgstr "禁用选中的任务"
#: django_celery_beat/admin.py:209
msgid "Toggle activity of selected tasks"
msgstr "切换选中的任务"
#: django_celery_beat/admin.py:230
#, fuzzy, python-brace-format
#| msgid "task \"{0}\" not found"
msgid "task \"{not_found_task_name}\" not found"
msgstr "未找到\"{0}\"任务"
#: django_celery_beat/admin.py:246
#, python-brace-format
msgid "{0} task{1} {2} successfully run"
msgstr "{0} 任务{1} {2} 启动成功"
#: django_celery_beat/admin.py:252
msgid "Run selected tasks"
msgstr "运行选中的任务"
#: django_celery_beat/apps.py:13
msgid "Periodic Tasks"
msgstr "周期任务"
#: django_celery_beat/models.py:31
msgid "Days"
msgstr "天"
#: django_celery_beat/models.py:32
msgid "Hours"
msgstr "小时"
#: django_celery_beat/models.py:33
msgid "Minutes"
msgstr "分钟"
#: django_celery_beat/models.py:34
msgid "Seconds"
msgstr "秒"
#: django_celery_beat/models.py:35
msgid "Microseconds"
msgstr "毫秒"
#: django_celery_beat/models.py:39
msgid "Day"
msgstr "天"
#: django_celery_beat/models.py:40
msgid "Hour"
msgstr "小时"
#: django_celery_beat/models.py:41
msgid "Minute"
msgstr "分钟"
#: django_celery_beat/models.py:42
msgid "Second"
msgstr "秒"
#: django_celery_beat/models.py:43
msgid "Microsecond"
msgstr "毫秒"
#: django_celery_beat/models.py:47
msgid "Astronomical dawn"
msgstr "天文黎明"
#: django_celery_beat/models.py:48
msgid "Civil dawn"
msgstr "民事黎明"
#: django_celery_beat/models.py:49
msgid "Nautical dawn"
msgstr "航海黎明"
#: django_celery_beat/models.py:50
msgid "Astronomical dusk"
msgstr "天文黄昏"
#: django_celery_beat/models.py:51
msgid "Civil dusk"
msgstr "民事黄昏"
#: django_celery_beat/models.py:52
msgid "Nautical dusk"
msgstr "航海黄昏"
#: django_celery_beat/models.py:53
msgid "Solar noon"
msgstr "正午"
#: django_celery_beat/models.py:54
msgid "Sunrise"
msgstr "日出"
#: django_celery_beat/models.py:55
msgid "Sunset"
msgstr "日落"
#: django_celery_beat/models.py:89
msgid "Solar Event"
msgstr "日程事件"
#: django_celery_beat/models.py:90
msgid "The type of solar event when the job should run"
msgstr "当任务应该执行时的日程事件类型"
#: django_celery_beat/models.py:94
msgid "Latitude"
msgstr "纬度"
#: django_celery_beat/models.py:95
msgid "Run the task when the event happens at this latitude"
msgstr "当在此纬度发生事件时执行任务"
#: django_celery_beat/models.py:100
msgid "Longitude"
msgstr "经度"
#: django_celery_beat/models.py:101
msgid "Run the task when the event happens at this longitude"
msgstr "当在此经度发生事件时执行任务"
#: django_celery_beat/models.py:108
msgid "solar event"
msgstr "日程事件"
#: django_celery_beat/models.py:109
msgid "solar events"
msgstr "日程事件"
#: django_celery_beat/models.py:159
msgid "Number of Periods"
msgstr "周期数"
#: django_celery_beat/models.py:160
msgid "Number of interval periods to wait before running the task again"
msgstr "再次执行任务之前要等待的间隔周期数"
#: django_celery_beat/models.py:166
msgid "Interval Period"
msgstr "间隔周期"
#: django_celery_beat/models.py:167
msgid "The type of period between task runs (Example: days)"
msgstr "任务每次执行之间的时间间隔类型(例如:天)"
#: django_celery_beat/models.py:173
msgid "interval"
msgstr "间隔"
#: django_celery_beat/models.py:174
msgid "intervals"
msgstr "间隔"
#: django_celery_beat/models.py:201
msgid "every {}"
msgstr "每 {}"
#: django_celery_beat/models.py:206
msgid "every {} {}"
msgstr "每 {} {}"
#: django_celery_beat/models.py:217
msgid "Clock Time"
msgstr "定时时间"
#: django_celery_beat/models.py:218
msgid "Run the task at clocked time"
msgstr "在定时时间执行任务"
#: django_celery_beat/models.py:224 .\models.py:225
msgid "clocked"
msgstr "定时"
#: django_celery_beat/models.py:265
msgid "Minute(s)"
msgstr "分钟"
#: django_celery_beat/models.py:267
msgid "Cron Minutes to Run. Use \"*\" for \"all\". (Example: \"0,30\")"
msgstr "计划执行的分钟。 将\"*\"用作\"all\"。(例如:\"0,30\""
#: django_celery_beat/models.py:272
msgid "Hour(s)"
msgstr "小时"
#: django_celery_beat/models.py:274
msgid "Cron Hours to Run. Use \"*\" for \"all\". (Example: \"8,20\")"
msgstr "计划执行的小时。 将\"*\"用作\"all\"。(例如:\"8,20\""
#: django_celery_beat/models.py:279
msgid "Day(s) Of The Month"
msgstr "一个月的第几天"
#: django_celery_beat/models.py:281
msgid ""
"Cron Days Of The Month to Run. Use \"*\" for \"all\". (Example: \"1,15\")"
msgstr "计划执行的每个月的第几天。将\"*\"用作\"all\"。(例如:\"0,5\""
#: django_celery_beat/models.py:287
msgid "Month(s) Of The Year"
msgstr "一年的第几个月"
#: django_celery_beat/models.py:289
#, fuzzy
#| msgid ""
#| "Cron Months Of The Year to Run. Use \"*\" for \"all\". (Example: \"0,6\")"
msgid ""
"Cron Months (1-12) Of The Year to Run. Use \"*\" for \"all\". (Example: "
"\"1,12\")"
msgstr "计划执行的每一年的第几个月。将\"*\"用作\"all\"。(例如:\"0,5\""
#: django_celery_beat/models.py:295
msgid "Day(s) Of The Week"
msgstr "一个星期的第几天"
#: django_celery_beat/models.py:297
#, fuzzy
#| msgid ""
#| "Cron Days Of The Week to Run. Use \"*\" for \"all\". (Example: \"0,5\")"
msgid ""
"Cron Days Of The Week to Run. Use \"*\" for \"all\", Sunday is 0 or 7, "
"Monday is 1. (Example: \"0,5\")"
msgstr "计划执行的每周的第几天。将\"*\"用作\"all\"。(例如:\"0,5\""
#: django_celery_beat/models.py:305
msgid "Cron Timezone"
msgstr "计划任务的时区"
#: django_celery_beat/models.py:307
msgid "Timezone to Run the Cron Schedule on. Default is UTC."
msgstr "执行计划任务表的时区。 默认为UTC。"
#: django_celery_beat/models.py:313
msgid "crontab"
msgstr "计划任务"
#: django_celery_beat/models.py:314
msgid "crontabs"
msgstr "计划任务"
#: django_celery_beat/models.py:392
msgid "periodic task track"
msgstr "周期性任务追踪"
#: django_celery_beat/models.py:393
msgid "periodic task tracks"
msgstr "周期性任务追踪"
#: django_celery_beat/models.py:417
msgid "Name"
msgstr "任务名"
#: django_celery_beat/models.py:418
msgid "Short Description For This Task"
msgstr "该任务的简短说明"
#: django_celery_beat/models.py:423
msgid ""
"The Name of the Celery Task that Should be Run. (Example: \"proj.tasks."
"import_contacts\")"
msgstr "被执行的任务的名称。(例如:\"proj.tasks.import_contacts\")"
#: django_celery_beat/models.py:431
msgid "Interval Schedule"
msgstr "间隔时间表"
#: django_celery_beat/models.py:432
msgid ""
"Interval Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr "执行任务的间隔时间表。 仅设置一种时间表类型,将其他保留为空。"
#: django_celery_beat/models.py:437
msgid "Crontab Schedule"
msgstr "计划时间表"
#: django_celery_beat/models.py:438
msgid ""
"Crontab Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr "执行任务的计划时间表。 仅设置一种时间表类型,将其他保留为空。"
#: django_celery_beat/models.py:443
msgid "Solar Schedule"
msgstr "日程时间表"
#: django_celery_beat/models.py:444
msgid ""
"Solar Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr "执行任务的日程时间表。 仅设置一种时间表类型,将其他保留为空。"
#: django_celery_beat/models.py:449
msgid "Clocked Schedule"
msgstr "定时时间表"
#: django_celery_beat/models.py:450
msgid ""
"Clocked Schedule to run the task on. Set only one schedule type, leave the "
"others null."
msgstr "执行任务的定时时间表。 仅设置一种时间表类型,将其他保留为空。"
#: django_celery_beat/models.py:456
msgid "Positional Arguments"
msgstr "位置参数"
#: django_celery_beat/models.py:458
msgid "JSON encoded positional arguments (Example: [\"arg1\", \"arg2\"])"
msgstr "JSON编码的位置参数(例如: [\"arg1\", \"arg2\"])"
#: django_celery_beat/models.py:463
msgid "Keyword Arguments"
msgstr "关键字参数"
#: django_celery_beat/models.py:465
msgid "JSON encoded keyword arguments (Example: {\"argument\": \"value\"})"
msgstr "JSON编码的关键字参数(例如: {\"argument\": \"value\"})"
#: django_celery_beat/models.py:471
msgid "Queue Override"
msgstr "队列覆盖"
#: django_celery_beat/models.py:473
msgid "Queue defined in CELERY_TASK_QUEUES. Leave None for default queuing."
msgstr "在 CELERY_TASK_QUEUES 定义的队列。保留空以进行默认排队。"
#: django_celery_beat/models.py:482
msgid "Exchange"
msgstr "交换机"
#: django_celery_beat/models.py:483
msgid "Override Exchange for low-level AMQP routing"
msgstr "覆盖交换机以进行低层级AMQP路由"
#: django_celery_beat/models.py:487
msgid "Routing Key"
msgstr "路由键"
#: django_celery_beat/models.py:488
msgid "Override Routing Key for low-level AMQP routing"
msgstr "覆盖路由键以进行低层级AMQP路由"
#: django_celery_beat/models.py:492
msgid "AMQP Message Headers"
msgstr "AMQP消息头"
#: django_celery_beat/models.py:493
msgid "JSON encoded message headers for the AMQP message."
msgstr "AMQP消息的JSON编码消息头。"
#: django_celery_beat/models.py:499
msgid "Priority"
msgstr "优先级"
#: django_celery_beat/models.py:501
msgid ""
"Priority Number between 0 and 255. Supported by: RabbitMQ, Redis (priority "
"reversed, 0 is highest)."
msgstr ""
"优先级数字介于0和255之间。支持者RabbitMQRedis优先级颠倒0是最高。"
#: django_celery_beat/models.py:506
msgid "Expires Datetime"
msgstr "过期时刻"
#: django_celery_beat/models.py:508
msgid ""
"Datetime after which the schedule will no longer trigger the task to run"
msgstr "过期时刻,计划表将在此时刻后不再触发任务执行"
#: django_celery_beat/models.py:513
msgid "Expires timedelta with seconds"
msgstr "过期时间间隔,以秒为单位"
#: django_celery_beat/models.py:515
msgid ""
"Timedelta with seconds which the schedule will no longer trigger the task to "
"run"
msgstr "再过该秒后,不再触发任务执行"
#: django_celery_beat/models.py:521
msgid "One-off Task"
msgstr "一次任务"
#: django_celery_beat/models.py:523
msgid "If True, the schedule will only run the task a single time"
msgstr "如果为True则计划将仅运行任务一次"
#: django_celery_beat/models.py:527
msgid "Start Datetime"
msgstr "开始时间"
#: django_celery_beat/models.py:529
msgid "Datetime when the schedule should begin triggering the task to run"
msgstr "时间表开始触发任务执行的时刻"
#: django_celery_beat/models.py:534
msgid "Enabled"
msgstr "已启用"
#: django_celery_beat/models.py:535
msgid "Set to False to disable the schedule"
msgstr "设置为False可禁用时间表"
#: django_celery_beat/models.py:540
msgid "Last Run Datetime"
msgstr "上次运行时刻"
#: django_celery_beat/models.py:542
msgid ""
"Datetime that the schedule last triggered the task to run. Reset to None if "
"enabled is set to False."
msgstr "最后一次触发任务执行的时刻。 如果enabled设置为False则重置为None。"
#: django_celery_beat/models.py:547
msgid "Total Run Count"
msgstr "总运行次数"
#: django_celery_beat/models.py:549
msgid "Running count of how many times the schedule has triggered the task"
msgstr "任务执行多少次的运行计数"
#: django_celery_beat/models.py:554
msgid "Last Modified"
msgstr "最后修改"
#: django_celery_beat/models.py:555
msgid "Datetime that this PeriodicTask was last modified"
msgstr "该周期性任务的最后修改时刻"
#: django_celery_beat/models.py:559
msgid "Description"
msgstr "描述"
#: django_celery_beat/models.py:561
msgid "Detailed description about the details of this Periodic Task"
msgstr "有关此周期性任务的详细信息"
#: django_celery_beat/models.py:570
msgid "periodic task"
msgstr "周期性任务"
#: django_celery_beat/models.py:571
msgid "periodic tasks"
msgstr "周期性任务"
#: django_celery_beat/templates/admin/djcelery/change_list.html:6
msgid "Home"
msgstr "首页"

View File

@@ -0,0 +1,129 @@
# Generated by Django 1.9.5 on 2016-08-04 02:13
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='CrontabSchedule',
fields=[
('id', models.AutoField(
auto_created=True, primary_key=True,
serialize=False, verbose_name='ID')),
('minute', models.CharField(
default='*', max_length=64, verbose_name='minute')),
('hour', models.CharField(
default='*', max_length=64, verbose_name='hour')),
('day_of_week', models.CharField(
default='*', max_length=64, verbose_name='day of week')),
('day_of_month', models.CharField(
default='*', max_length=64, verbose_name='day of month')),
('month_of_year', models.CharField(
default='*', max_length=64, verbose_name='month of year')),
],
options={
'ordering': [
'month_of_year', 'day_of_month',
'day_of_week', 'hour', 'minute',
],
'verbose_name': 'crontab',
'verbose_name_plural': 'crontabs',
},
),
migrations.CreateModel(
name='IntervalSchedule',
fields=[
('id', models.AutoField(
auto_created=True, primary_key=True,
serialize=False, verbose_name='ID')),
('every', models.IntegerField(verbose_name='every')),
('period', models.CharField(
choices=[
('days', 'Days'),
('hours', 'Hours'),
('minutes', 'Minutes'),
('seconds', 'Seconds'),
('microseconds', 'Microseconds'),
],
max_length=24,
verbose_name='period')),
],
options={
'ordering': ['period', 'every'],
'verbose_name': 'interval',
'verbose_name_plural': 'intervals',
},
),
migrations.CreateModel(
name='PeriodicTask',
fields=[
('id', models.AutoField(
auto_created=True, primary_key=True,
serialize=False, verbose_name='ID')),
('name', models.CharField(
help_text='Useful description', max_length=200,
unique=True, verbose_name='name')),
('task', models.CharField(
max_length=200, verbose_name='task name')),
('args', models.TextField(
blank=True, default='[]',
help_text='JSON encoded positional arguments',
verbose_name='Arguments')),
('kwargs', models.TextField(
blank=True, default='{}',
help_text='JSON encoded keyword arguments',
verbose_name='Keyword arguments')),
('queue', models.CharField(
blank=True, default=None,
help_text='Queue defined in CELERY_TASK_QUEUES',
max_length=200, null=True, verbose_name='queue')),
('exchange', models.CharField(
blank=True, default=None, max_length=200,
null=True, verbose_name='exchange')),
('routing_key', models.CharField(
blank=True, default=None,
max_length=200, null=True, verbose_name='routing key')),
('expires', models.DateTimeField(
blank=True, null=True, verbose_name='expires')),
('enabled', models.BooleanField(
default=True, verbose_name='enabled')),
('last_run_at', models.DateTimeField(
blank=True, editable=False, null=True)),
('total_run_count', models.PositiveIntegerField(
default=0, editable=False)),
('date_changed', models.DateTimeField(auto_now=True)),
('description', models.TextField(
blank=True, verbose_name='description')),
('crontab', models.ForeignKey(
blank=True, help_text='Use one of interval/crontab',
null=True, on_delete=django.db.models.deletion.CASCADE,
to='django_celery_beat.CrontabSchedule',
verbose_name='crontab')),
('interval', models.ForeignKey(
blank=True, null=True,
on_delete=django.db.models.deletion.CASCADE,
to='django_celery_beat.IntervalSchedule',
verbose_name='interval')),
],
options={
'verbose_name': 'periodic task',
'verbose_name_plural': 'periodic tasks',
},
),
migrations.CreateModel(
name='PeriodicTasks',
fields=[
('ident', models.SmallIntegerField(
default=1, primary_key=True,
serialize=False, unique=True)),
('last_update', models.DateTimeField()),
],
),
]

View File

@@ -0,0 +1,49 @@
# Generated by Django 1.10.3 on 2016-11-18 03:46
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('django_celery_beat', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='SolarSchedule',
fields=[
('id', models.AutoField(
auto_created=True, primary_key=True,
serialize=False, verbose_name='ID')),
('event', models.CharField(
choices=[('dusk_nautical', 'dusk_nautical'),
('dawn_astronomical', 'dawn_astronomical'),
('dawn_nautical', 'dawn_nautical'),
('dawn_civil', 'dawn_civil'),
('sunset', 'sunset'),
('solar_noon', 'solar_noon'),
('dusk_astronomical', 'dusk_astronomical'),
('sunrise', 'sunrise'),
('dusk_civil', 'dusk_civil')],
max_length=24, verbose_name='event')),
('latitude', models.DecimalField(
decimal_places=6, max_digits=9, verbose_name='latitude')),
('longitude', models.DecimalField(
decimal_places=6, max_digits=9, verbose_name='latitude')),
],
options={
'ordering': ['event', 'latitude', 'longitude'],
'verbose_name': 'solar',
'verbose_name_plural': 'solars',
},
),
migrations.AddField(
model_name='periodictask',
name='solar',
field=models.ForeignKey(
blank=True, help_text='Use a solar schedule',
null=True, on_delete=django.db.models.deletion.CASCADE,
to='django_celery_beat.SolarSchedule', verbose_name='solar'),
),
]

View File

@@ -0,0 +1,23 @@
# Generated by Django 1.9.11 on 2016-12-09 00:49
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('django_celery_beat', '0002_auto_20161118_0346'),
]
operations = [
migrations.AlterModelOptions(
name='solarschedule',
options={
'ordering': ('event', 'latitude', 'longitude'),
'verbose_name': 'solar event',
'verbose_name_plural': 'solar events'},
),
migrations.AlterUniqueTogether(
name='solarschedule',
unique_together=set([('event', 'latitude', 'longitude')]),
),
]

View File

@@ -0,0 +1,19 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('django_celery_beat', '0003_auto_20161209_0049'),
]
operations = [
migrations.AlterField(
model_name='solarschedule',
name='longitude',
field=models.DecimalField(
verbose_name='longitude',
max_digits=9,
decimal_places=6),
),
]

View File

@@ -0,0 +1,28 @@
# Generated by Django 1.9.1 on 2017-11-01 15:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('django_celery_beat', '0004_auto_20170221_0000'),
]
operations = [
migrations.AlterField(
model_name='solarschedule',
name='event',
field=models.CharField(choices=[
('dawn_astronomical', 'dawn_astronomical'),
('dawn_civil', 'dawn_civil'),
('dawn_nautical', 'dawn_nautical'),
('dusk_astronomical', 'dusk_astronomical'),
('dusk_civil', 'dusk_civil'),
('dusk_nautical', 'dusk_nautical'),
('solar_noon', 'solar_noon'),
('sunrise', 'sunrise'),
('sunset', 'sunset')
],
max_length=24, verbose_name='event'),
),
]

View File

@@ -0,0 +1,30 @@
# Generated by Django 2.0.1 on 2018-02-10 12:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('django_celery_beat', '0005_add_solarschedule_events_choices'),
]
operations = [
migrations.AlterField(
model_name='crontabschedule',
name='day_of_month',
field=models.CharField(default='*', max_length=124,
verbose_name='day of month'),
),
migrations.AlterField(
model_name='crontabschedule',
name='hour',
field=models.CharField(default='*', max_length=96,
verbose_name='hour'),
),
migrations.AlterField(
model_name='crontabschedule',
name='minute',
field=models.CharField(default='*', max_length=240,
verbose_name='minute'),
),
]

View File

@@ -0,0 +1,51 @@
# Generated by Django 1.11.7 on 2018-03-22 16:32
from django.db import migrations, models
import timezone_field.fields
class Migration(migrations.Migration):
dependencies = [
('django_celery_beat', '0005_add_solarschedule_events_choices'),
# ('django_celery_beat', '0006_auto_20180210_1226'),
]
operations = [
migrations.AlterModelOptions(
name='crontabschedule',
options={
'ordering': [
'month_of_year', 'day_of_month',
'day_of_week', 'hour', 'minute', 'timezone'
],
'verbose_name': 'crontab',
'verbose_name_plural': 'crontabs'
},
),
migrations.AddField(
model_name='crontabschedule',
name='timezone',
field=timezone_field.fields.TimeZoneField(default='UTC'),
),
migrations.AlterField(
model_name='crontabschedule',
name='day_of_month',
field=models.CharField(
default='*', max_length=124, verbose_name='day of month'
),
),
migrations.AlterField(
model_name='crontabschedule',
name='hour',
field=models.CharField(
default='*', max_length=96, verbose_name='hour'
),
),
migrations.AlterField(
model_name='crontabschedule',
name='minute',
field=models.CharField(
default='*', max_length=240, verbose_name='minute'
),
),
]

View File

@@ -0,0 +1,28 @@
# Generated by Django 2.0.6 on 2018-10-22 05:20
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
# depends on higher numbers due to a squashed migration
# that was later removed due to migration issues it caused
('django_celery_beat', '0005_add_solarschedule_events_choices'),
('django_celery_beat', '0006_auto_20180210_1226'),
('django_celery_beat', '0006_auto_20180322_0932'),
('django_celery_beat', '0007_auto_20180521_0826'),
('django_celery_beat', '0008_auto_20180914_1922'),
]
operations = [
migrations.AddField(
model_name='periodictask',
name='priority',
field=models.PositiveIntegerField(
blank=True,
default=None,
null=True,
validators=[django.core.validators.MaxValueValidator(255)],
verbose_name='priority'),
),
]

View File

@@ -0,0 +1,25 @@
# Generated by Django 1.10.7 on 2018-05-21 08:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('django_celery_beat', '0006_auto_20180322_0932'),
]
operations = [
migrations.AddField(
model_name='periodictask',
name='one_off',
field=models.BooleanField(default=False,
verbose_name='one-off task'),
),
migrations.AddField(
model_name='periodictask',
name='start_time',
field=models.DateTimeField(blank=True,
null=True,
verbose_name='start_time'),
),
]

View File

@@ -0,0 +1,57 @@
# Generated by Django 2.0.3 on 2018-09-14 19:22
from django.db import migrations, models
from django_celery_beat import validators
class Migration(migrations.Migration):
dependencies = [
('django_celery_beat', '0007_auto_20180521_0826'),
]
operations = [
migrations.AlterField(
model_name='crontabschedule',
name='day_of_month',
field=models.CharField(
default='*', max_length=124,
validators=[validators.day_of_month_validator],
verbose_name='day of month'
),
),
migrations.AlterField(
model_name='crontabschedule',
name='day_of_week',
field=models.CharField(
default='*', max_length=64,
validators=[validators.day_of_week_validator],
verbose_name='day of week'
),
),
migrations.AlterField(
model_name='crontabschedule',
name='hour',
field=models.CharField(
default='*', max_length=96,
validators=[validators.hour_validator],
verbose_name='hour'
),
),
migrations.AlterField(
model_name='crontabschedule',
name='minute',
field=models.CharField(
default='*', max_length=240,
validators=[validators.minute_validator],
verbose_name='minute'
),
),
migrations.AlterField(
model_name='crontabschedule',
name='month_of_year',
field=models.CharField(
default='*', max_length=64,
validators=[validators.month_of_year_validator],
verbose_name='month of year'
),
),
]

View File

@@ -0,0 +1,22 @@
# Generated by Django 2.1.5 on 2019-02-09 19:33
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('django_celery_beat', '0006_periodictask_priority'),
]
operations = [
migrations.AddField(
model_name='periodictask',
name='headers',
field=models.TextField(
blank=True,
default='{}',
help_text='JSON encoded message headers',
verbose_name='Message headers'
),
),
]

View File

@@ -0,0 +1,174 @@
# Generated by Django 1.11.20 on 2019-04-29 03:26
# this file is auto-generated so don't do flake8 on it
# flake8: noqa
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
import django_celery_beat.validators
import timezone_field.fields
class Migration(migrations.Migration):
dependencies = [
('django_celery_beat', '0009_periodictask_headers'),
]
operations = [
migrations.AlterField(
model_name='crontabschedule',
name='day_of_month',
field=models.CharField(default='*', help_text='Cron Days Of The Month to Run. Use "*" for "all". (Example: "1,15")', max_length=124, validators=[django_celery_beat.validators.day_of_month_validator], verbose_name='Day(s) Of The Month'),
),
migrations.AlterField(
model_name='crontabschedule',
name='day_of_week',
field=models.CharField(default='*', help_text='Cron Days Of The Week to Run. Use "*" for "all". (Example: "0,5")', max_length=64, validators=[django_celery_beat.validators.day_of_week_validator], verbose_name='Day(s) Of The Week'),
),
migrations.AlterField(
model_name='crontabschedule',
name='hour',
field=models.CharField(default='*', help_text='Cron Hours to Run. Use "*" for "all". (Example: "8,20")', max_length=96, validators=[django_celery_beat.validators.hour_validator], verbose_name='Hour(s)'),
),
migrations.AlterField(
model_name='crontabschedule',
name='minute',
field=models.CharField(default='*', help_text='Cron Minutes to Run. Use "*" for "all". (Example: "0,30")', max_length=240, validators=[django_celery_beat.validators.minute_validator], verbose_name='Minute(s)'),
),
migrations.AlterField(
model_name='crontabschedule',
name='month_of_year',
field=models.CharField(default='*', help_text='Cron Months Of The Year to Run. Use "*" for "all". (Example: "0,6")', max_length=64, validators=[django_celery_beat.validators.month_of_year_validator], verbose_name='Month(s) Of The Year'),
),
migrations.AlterField(
model_name='crontabschedule',
name='timezone',
field=timezone_field.fields.TimeZoneField(default='UTC', help_text='Timezone to Run the Cron Schedule on. Default is UTC.', verbose_name='Cron Timezone'),
),
migrations.AlterField(
model_name='intervalschedule',
name='every',
field=models.IntegerField(help_text='Number of interval periods to wait before running the task again', validators=[django.core.validators.MinValueValidator(1)], verbose_name='Number of Periods'),
),
migrations.AlterField(
model_name='intervalschedule',
name='period',
field=models.CharField(choices=[('days', 'Days'), ('hours', 'Hours'), ('minutes', 'Minutes'), ('seconds', 'Seconds'), ('microseconds', 'Microseconds')], help_text='The type of period between task runs (Example: days)', max_length=24, verbose_name='Interval Period'),
),
migrations.AlterField(
model_name='periodictask',
name='args',
field=models.TextField(blank=True, default='[]', help_text='JSON encoded positional arguments (Example: ["arg1", "arg2"])', verbose_name='Positional Arguments'),
),
migrations.AlterField(
model_name='periodictask',
name='crontab',
field=models.ForeignKey(blank=True, help_text='Crontab Schedule to run the task on. Set only one schedule type, leave the others null.', null=True, on_delete=django.db.models.deletion.CASCADE, to='django_celery_beat.CrontabSchedule', verbose_name='Crontab Schedule'),
),
migrations.AlterField(
model_name='periodictask',
name='date_changed',
field=models.DateTimeField(auto_now=True, help_text='Datetime that this PeriodicTask was last modified', verbose_name='Last Modified'),
),
migrations.AlterField(
model_name='periodictask',
name='description',
field=models.TextField(blank=True, help_text='Detailed description about the details of this Periodic Task', verbose_name='Description'),
),
migrations.AlterField(
model_name='periodictask',
name='enabled',
field=models.BooleanField(default=True, help_text='Set to False to disable the schedule', verbose_name='Enabled'),
),
migrations.AlterField(
model_name='periodictask',
name='exchange',
field=models.CharField(blank=True, default=None, help_text='Override Exchange for low-level AMQP routing', max_length=200, null=True, verbose_name='Exchange'),
),
migrations.AlterField(
model_name='periodictask',
name='expires',
field=models.DateTimeField(blank=True, help_text='Datetime after which the schedule will no longer trigger the task to run', null=True, verbose_name='Expires Datetime'),
),
migrations.AlterField(
model_name='periodictask',
name='headers',
field=models.TextField(blank=True, default='{}', help_text='JSON encoded message headers for the AMQP message.', verbose_name='AMQP Message Headers'),
),
migrations.AlterField(
model_name='periodictask',
name='interval',
field=models.ForeignKey(blank=True, help_text='Interval Schedule to run the task on. Set only one schedule type, leave the others null.', null=True, on_delete=django.db.models.deletion.CASCADE, to='django_celery_beat.IntervalSchedule', verbose_name='Interval Schedule'),
),
migrations.AlterField(
model_name='periodictask',
name='kwargs',
field=models.TextField(blank=True, default='{}', help_text='JSON encoded keyword arguments (Example: {"argument": "value"})', verbose_name='Keyword Arguments'),
),
migrations.AlterField(
model_name='periodictask',
name='last_run_at',
field=models.DateTimeField(blank=True, editable=False, help_text='Datetime that the schedule last triggered the task to run. Reset to None if enabled is set to False.', null=True, verbose_name='Last Run Datetime'),
),
migrations.AlterField(
model_name='periodictask',
name='name',
field=models.CharField(help_text='Short Description For This Task', max_length=200, unique=True, verbose_name='Name'),
),
migrations.AlterField(
model_name='periodictask',
name='one_off',
field=models.BooleanField(default=False, help_text='If True, the schedule will only run the task a single time', verbose_name='One-off Task'),
),
migrations.AlterField(
model_name='periodictask',
name='priority',
field=models.PositiveIntegerField(blank=True, default=None, help_text='Priority Number between 0 and 255. Supported by: RabbitMQ, Redis (priority reversed, 0 is highest).', null=True, validators=[django.core.validators.MaxValueValidator(255)], verbose_name='Priority'),
),
migrations.AlterField(
model_name='periodictask',
name='queue',
field=models.CharField(blank=True, default=None, help_text='Queue defined in CELERY_TASK_QUEUES. Leave None for default queuing.', max_length=200, null=True, verbose_name='Queue Override'),
),
migrations.AlterField(
model_name='periodictask',
name='routing_key',
field=models.CharField(blank=True, default=None, help_text='Override Routing Key for low-level AMQP routing', max_length=200, null=True, verbose_name='Routing Key'),
),
migrations.AlterField(
model_name='periodictask',
name='solar',
field=models.ForeignKey(blank=True, help_text='Solar Schedule to run the task on. Set only one schedule type, leave the others null.', null=True, on_delete=django.db.models.deletion.CASCADE, to='django_celery_beat.SolarSchedule', verbose_name='Solar Schedule'),
),
migrations.AlterField(
model_name='periodictask',
name='start_time',
field=models.DateTimeField(blank=True, help_text='Datetime when the schedule should begin triggering the task to run', null=True, verbose_name='Start Datetime'),
),
migrations.AlterField(
model_name='periodictask',
name='task',
field=models.CharField(help_text='The Name of the Celery Task that Should be Run. (Example: "proj.tasks.import_contacts")', max_length=200, verbose_name='Task Name'),
),
migrations.AlterField(
model_name='periodictask',
name='total_run_count',
field=models.PositiveIntegerField(default=0, editable=False, help_text='Running count of how many times the schedule has triggered the task', verbose_name='Total Run Count'),
),
migrations.AlterField(
model_name='solarschedule',
name='event',
field=models.CharField(choices=[('dawn_astronomical', 'dawn_astronomical'), ('dawn_civil', 'dawn_civil'), ('dawn_nautical', 'dawn_nautical'), ('dusk_astronomical', 'dusk_astronomical'), ('dusk_civil', 'dusk_civil'), ('dusk_nautical', 'dusk_nautical'), ('solar_noon', 'solar_noon'), ('sunrise', 'sunrise'), ('sunset', 'sunset')], help_text='The type of solar event when the job should run', max_length=24, verbose_name='Solar Event'),
),
migrations.AlterField(
model_name='solarschedule',
name='latitude',
field=models.DecimalField(decimal_places=6, help_text='Run the task when the event happens at this latitude', max_digits=9, validators=[django.core.validators.MinValueValidator(-90), django.core.validators.MaxValueValidator(90)], verbose_name='Latitude'),
),
migrations.AlterField(
model_name='solarschedule',
name='longitude',
field=models.DecimalField(decimal_places=6, help_text='Run the task when the event happens at this longitude', max_digits=9, validators=[django.core.validators.MinValueValidator(-180), django.core.validators.MaxValueValidator(180)], verbose_name='Longitude'),
),
]

View File

@@ -0,0 +1,32 @@
# Generated by Django 2.2 on 2019-05-08 01:53
# flake8: noqa
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('django_celery_beat', '0010_auto_20190429_0326'),
]
operations = [
migrations.CreateModel(
name='ClockedSchedule',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('clocked_time', models.DateTimeField(help_text='Run the task at clocked time', verbose_name='Clock Time')),
('enabled', models.BooleanField(default=True, editable=False, help_text='Set to False to disable the schedule', verbose_name='Enabled')),
],
options={
'verbose_name': 'clocked',
'verbose_name_plural': 'clocked',
'ordering': ['clocked_time'],
},
),
migrations.AddField(
model_name='periodictask',
name='clocked',
field=models.ForeignKey(blank=True, help_text='Clocked Schedule to run the task on. Set only one schedule type, leave the others null.', null=True, on_delete=django.db.models.deletion.CASCADE, to='django_celery_beat.ClockedSchedule', verbose_name='Clocked Schedule'),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 2.2.4 on 2019-08-30 00:46
# flake8: noqa
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('django_celery_beat', '0011_auto_20190508_0153'),
]
operations = [
migrations.AddField(
model_name='periodictask',
name='expire_seconds',
field=models.PositiveIntegerField(blank=True, help_text='Timedelta with seconds which the schedule will no longer trigger the task to run', null=True, verbose_name='Expires timedelta with seconds'),
),
]

View File

@@ -0,0 +1,20 @@
# Generated by Django 3.0.6 on 2020-06-09 07:27
# flake8: noqa
from django.db import migrations
import django_celery_beat.models
import timezone_field.fields
class Migration(migrations.Migration):
dependencies = [
('django_celery_beat', '0012_periodictask_expire_seconds'),
]
operations = [
migrations.AlterField(
model_name='crontabschedule',
name='timezone',
field=timezone_field.fields.TimeZoneField(default=django_celery_beat.models.crontab_schedule_celery_timezone, help_text='Timezone to Run the Cron Schedule on. Default is UTC.', verbose_name='Cron Timezone'),
),
]

View File

@@ -0,0 +1,17 @@
# Generated by Django 2.2.4 on 2019-08-30 00:46
# flake8: noqa
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('django_celery_beat', '0013_auto_20200609_0727'),
]
operations = [
migrations.RemoveField(
model_name='clockedschedule',
name='enabled',
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 3.0.6 on 2020-12-13 15:00
# flake8: noqa
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('django_celery_beat', '0014_remove_clockedschedule_enabled'),
]
operations = [
migrations.AlterField(
model_name='solarschedule',
name='event',
field=models.CharField(choices=[('dawn_astronomical', 'Astronomical dawn'), ('dawn_civil', 'Civil dawn'), ('dawn_nautical', 'Nautical dawn'), ('dusk_astronomical', 'Astronomical dusk'), ('dusk_civil', 'Civil dusk'), ('dusk_nautical', 'Nautical dusk'), ('solar_noon', 'Solar noon'), ('sunrise', 'Sunrise'), ('sunset', 'Sunset')], help_text='The type of solar event when the job should run', max_length=24, verbose_name='Solar Event'),
),
]

View File

@@ -0,0 +1,25 @@
# Generated by Django 4.0.3 on 2022-03-21 20:20
# flake8: noqa
from django.db import migrations
import django_celery_beat.models
import timezone_field.fields
class Migration(migrations.Migration):
dependencies = [
('django_celery_beat', '0015_edit_solarschedule_events_choices'),
]
operations = [
migrations.AlterField(
model_name='crontabschedule',
name='timezone',
field=timezone_field.fields.TimeZoneField(
default=
django_celery_beat.models.crontab_schedule_celery_timezone,
help_text=
'Timezone to Run the Cron Schedule on. Default is UTC.',
use_pytz=False, verbose_name='Cron Timezone'),
),
]

View File

@@ -0,0 +1,19 @@
# Generated by Django 4.1.4 on 2022-12-17 09:21
from django.db import migrations, models
import django_celery_beat.validators
class Migration(migrations.Migration):
dependencies = [
('django_celery_beat', '0016_alter_crontabschedule_timezone'),
]
operations = [
migrations.AlterField(
model_name='crontabschedule',
name='month_of_year',
field=models.CharField(default='*', help_text='Cron Months (1-12) Of The Year to Run. Use "*" for "all". (Example: "1,12")', max_length=64, validators=[django_celery_beat.validators.month_of_year_validator], verbose_name='Month(s) Of The Year'),
),
]

View File

@@ -0,0 +1,19 @@
# Generated by Django 3.2.16 on 2022-12-23 22:30
from django.db import migrations, models
import django_celery_beat.validators
class Migration(migrations.Migration):
dependencies = [
('django_celery_beat', '0017_alter_crontabschedule_month_of_year'),
]
operations = [
migrations.AlterField(
model_name='crontabschedule',
name='day_of_week',
field=models.CharField(default='*', help_text='Cron Days Of The Week to Run. Use "*" for "all", Sunday is 0 or 7, Monday is 1. (Example: "0,5")', max_length=64, validators=[django_celery_beat.validators.day_of_week_validator], verbose_name='Day(s) Of The Week'),
),
]

View File

@@ -0,0 +1,17 @@
# Generated by Django 5.0.1 on 2024-07-04 07:32
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('django_celery_beat', '0018_improve_crontab_helptext'),
]
operations = [
migrations.AlterModelOptions(
name='periodictasks',
options={'verbose_name': 'periodic task track', 'verbose_name_plural': 'periodic task tracks'},
),
]

View File

@@ -0,0 +1,676 @@
"""Database models."""
try:
from zoneinfo import available_timezones
except ImportError:
from backports.zoneinfo import available_timezones
from datetime import timedelta
import timezone_field
from celery import current_app, schedules
from cron_descriptor import (FormatException, MissingFieldException,
WrongArgumentException, get_description)
from django.conf import settings
from django.core.exceptions import MultipleObjectsReturned, ValidationError
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django.utils.translation import gettext_lazy as _
from . import querysets, validators
from .clockedschedule import clocked
from .tzcrontab import TzAwareCrontab
from .utils import make_aware, now
DAYS = 'days'
HOURS = 'hours'
MINUTES = 'minutes'
SECONDS = 'seconds'
MICROSECONDS = 'microseconds'
PERIOD_CHOICES = (
(DAYS, _('Days')),
(HOURS, _('Hours')),
(MINUTES, _('Minutes')),
(SECONDS, _('Seconds')),
(MICROSECONDS, _('Microseconds')),
)
SINGULAR_PERIODS = (
(DAYS, _('Day')),
(HOURS, _('Hour')),
(MINUTES, _('Minute')),
(SECONDS, _('Second')),
(MICROSECONDS, _('Microsecond')),
)
SOLAR_SCHEDULES = [
("dawn_astronomical", _("Astronomical dawn")),
("dawn_civil", _("Civil dawn")),
("dawn_nautical", _("Nautical dawn")),
("dusk_astronomical", _("Astronomical dusk")),
("dusk_civil", _("Civil dusk")),
("dusk_nautical", _("Nautical dusk")),
("solar_noon", _("Solar noon")),
("sunrise", _("Sunrise")),
("sunset", _("Sunset")),
]
def cronexp(field):
"""Representation of cron expression."""
return field and str(field).replace(' ', '') or '*'
def crontab_schedule_celery_timezone():
"""Return timezone string from Django settings ``CELERY_TIMEZONE`` variable.
If is not defined or is not a valid timezone, return ``"UTC"`` instead.
"""
try:
CELERY_TIMEZONE = getattr(
settings, '%s_TIMEZONE' % current_app.namespace)
except AttributeError:
return 'UTC'
if CELERY_TIMEZONE in available_timezones():
return CELERY_TIMEZONE
return 'UTC'
class SolarSchedule(models.Model):
"""Schedule following astronomical patterns.
Example: to run every sunrise in New York City:
>>> event='sunrise', latitude=40.7128, longitude=74.0060
"""
event = models.CharField(
max_length=24, choices=SOLAR_SCHEDULES,
verbose_name=_('Solar Event'),
help_text=_('The type of solar event when the job should run'),
)
latitude = models.DecimalField(
max_digits=9, decimal_places=6,
verbose_name=_('Latitude'),
help_text=_('Run the task when the event happens at this latitude'),
validators=[MinValueValidator(-90), MaxValueValidator(90)],
)
longitude = models.DecimalField(
max_digits=9, decimal_places=6,
verbose_name=_('Longitude'),
help_text=_('Run the task when the event happens at this longitude'),
validators=[MinValueValidator(-180), MaxValueValidator(180)],
)
class Meta:
"""Table information."""
verbose_name = _('solar event')
verbose_name_plural = _('solar events')
ordering = ('event', 'latitude', 'longitude')
unique_together = ('event', 'latitude', 'longitude')
@property
def schedule(self):
return schedules.solar(self.event,
self.latitude,
self.longitude,
nowfun=lambda: make_aware(now()))
@classmethod
def from_schedule(cls, schedule):
spec = {'event': schedule.event,
'latitude': schedule.lat,
'longitude': schedule.lon}
# we do not check for MultipleObjectsReturned exception here because
# the unique_together constraint safely prevents from duplicates
try:
return cls.objects.get(**spec)
except cls.DoesNotExist:
return cls(**spec)
def __str__(self):
return '{} ({}, {})'.format(
self.get_event_display(),
self.latitude,
self.longitude
)
class IntervalSchedule(models.Model):
"""Schedule executing on a regular interval.
Example: execute every 2 days:
>>> every=2, period=DAYS
"""
DAYS = DAYS
HOURS = HOURS
MINUTES = MINUTES
SECONDS = SECONDS
MICROSECONDS = MICROSECONDS
PERIOD_CHOICES = PERIOD_CHOICES
every = models.IntegerField(
null=False,
verbose_name=_('Number of Periods'),
help_text=_('Number of interval periods to wait before '
'running the task again'),
validators=[MinValueValidator(1)],
)
period = models.CharField(
max_length=24, choices=PERIOD_CHOICES,
verbose_name=_('Interval Period'),
help_text=_('The type of period between task runs (Example: days)'),
)
class Meta:
"""Table information."""
verbose_name = _('interval')
verbose_name_plural = _('intervals')
ordering = ['period', 'every']
@property
def schedule(self):
return schedules.schedule(
timedelta(**{self.period: self.every}),
nowfun=lambda: make_aware(now())
)
@classmethod
def from_schedule(cls, schedule, period=SECONDS):
every = max(schedule.run_every.total_seconds(), 0)
try:
return cls.objects.get(every=every, period=period)
except cls.DoesNotExist:
return cls(every=every, period=period)
except MultipleObjectsReturned:
return cls.objects.filter(every=every, period=period).first()
def __str__(self):
readable_period = None
if self.every == 1:
for period, _readable_period in SINGULAR_PERIODS:
if period == self.period:
readable_period = _readable_period.lower()
break
return _('every {}').format(readable_period)
for period, _readable_period in PERIOD_CHOICES:
if period == self.period:
readable_period = _readable_period.lower()
break
return _('every {} {}').format(self.every, readable_period)
@property
def period_singular(self):
return self.period[:-1]
class ClockedSchedule(models.Model):
"""clocked schedule."""
clocked_time = models.DateTimeField(
verbose_name=_('Clock Time'),
help_text=_('Run the task at clocked time'),
)
class Meta:
"""Table information."""
verbose_name = _('clocked')
verbose_name_plural = _('clocked')
ordering = ['clocked_time']
def __str__(self):
return f'{make_aware(self.clocked_time)}'
@property
def schedule(self):
c = clocked(clocked_time=self.clocked_time)
return c
@classmethod
def from_schedule(cls, schedule):
spec = {'clocked_time': schedule.clocked_time}
try:
return cls.objects.get(**spec)
except cls.DoesNotExist:
return cls(**spec)
except MultipleObjectsReturned:
return cls.objects.filter(**spec).first()
class CrontabSchedule(models.Model):
"""Timezone Aware Crontab-like schedule.
Example: Run every hour at 0 minutes for days of month 10-15:
>>> minute="0", hour="*", day_of_week="*",
... day_of_month="10-15", month_of_year="*"
"""
#
# The worst case scenario for day of month is a list of all 31 day numbers
# '[1, 2, ..., 31]' which has a length of 115. Likewise, minute can be
# 0..59 and hour can be 0..23. Ensure we can accomodate these by allowing
# 4 chars for each value (what we save on 0-9 accomodates the []).
# We leave the other fields at their historical length.
#
minute = models.CharField(
max_length=60 * 4, default='*',
verbose_name=_('Minute(s)'),
help_text=_(
'Cron Minutes to Run. Use "*" for "all". (Example: "0,30")'),
validators=[validators.minute_validator],
)
hour = models.CharField(
max_length=24 * 4, default='*',
verbose_name=_('Hour(s)'),
help_text=_(
'Cron Hours to Run. Use "*" for "all". (Example: "8,20")'),
validators=[validators.hour_validator],
)
day_of_month = models.CharField(
max_length=31 * 4, default='*',
verbose_name=_('Day(s) Of The Month'),
help_text=_(
'Cron Days Of The Month to Run. Use "*" for "all". '
'(Example: "1,15")'),
validators=[validators.day_of_month_validator],
)
month_of_year = models.CharField(
max_length=64, default='*',
verbose_name=_('Month(s) Of The Year'),
help_text=_(
'Cron Months (1-12) Of The Year to Run. Use "*" for "all". '
'(Example: "1,12")'),
validators=[validators.month_of_year_validator],
)
day_of_week = models.CharField(
max_length=64, default='*',
verbose_name=_('Day(s) Of The Week'),
help_text=_(
'Cron Days Of The Week to Run. Use "*" for "all", Sunday '
'is 0 or 7, Monday is 1. (Example: "0,5")'),
validators=[validators.day_of_week_validator],
)
timezone = timezone_field.TimeZoneField(
default=crontab_schedule_celery_timezone,
use_pytz=False,
verbose_name=_('Cron Timezone'),
help_text=_(
'Timezone to Run the Cron Schedule on. Default is UTC.'),
)
class Meta:
"""Table information."""
verbose_name = _('crontab')
verbose_name_plural = _('crontabs')
ordering = ['month_of_year', 'day_of_month',
'day_of_week', 'hour', 'minute', 'timezone']
@property
def human_readable(self):
try:
c = schedules.crontab(
minute=self.minute,
hour=self.hour,
day_of_week=self.day_of_week,
day_of_month=self.day_of_month,
month_of_year=self.month_of_year,
)
if c.day_of_week and set(c.day_of_week) == set(range(7)):
day_of_week = "*"
else:
day_of_week = cronexp(",".join(map(str, c.day_of_week)))
except ValueError:
day_of_week = cronexp(self.day_of_week)
cron_expression = '{} {} {} {} {}'.format(
cronexp(self.minute), cronexp(self.hour),
cronexp(self.day_of_month), cronexp(self.month_of_year),
day_of_week
)
try:
human_readable = get_description(cron_expression)
except (
MissingFieldException,
FormatException,
WrongArgumentException
):
return f'{cron_expression} {str(self.timezone)}'
return f'{human_readable} {str(self.timezone)}'
def __str__(self):
return '{} {} {} {} {} (m/h/dM/MY/d) {}'.format(
cronexp(self.minute), cronexp(self.hour),
cronexp(self.day_of_month), cronexp(self.month_of_year),
cronexp(self.day_of_week), str(self.timezone)
)
@property
def schedule(self):
crontab = schedules.crontab(
minute=self.minute,
hour=self.hour,
day_of_week=self.day_of_week,
day_of_month=self.day_of_month,
month_of_year=self.month_of_year,
)
if getattr(settings, 'DJANGO_CELERY_BEAT_TZ_AWARE', True):
crontab = TzAwareCrontab(
minute=self.minute,
hour=self.hour,
day_of_week=self.day_of_week,
day_of_month=self.day_of_month,
month_of_year=self.month_of_year,
tz=self.timezone
)
return crontab
@classmethod
def from_schedule(cls, schedule):
spec = {'minute': schedule._orig_minute,
'hour': schedule._orig_hour,
'day_of_week': schedule._orig_day_of_week,
'day_of_month': schedule._orig_day_of_month,
'month_of_year': schedule._orig_month_of_year,
'timezone': schedule.tz
}
try:
return cls.objects.get(**spec)
except cls.DoesNotExist:
return cls(**spec)
except MultipleObjectsReturned:
return cls.objects.filter(**spec).first()
def due_start_time(self, initial_start_time, tz):
start_time = initial_start_time.astimezone(tz)
start, ends_in, now = self.schedule.remaining_delta(start_time)
return start + ends_in
class PeriodicTasks(models.Model):
"""Helper table for tracking updates to periodic tasks.
This stores a single row with ``ident=1``. ``last_update`` is updated via
signals whenever anything changes in the :class:`~.PeriodicTask` model.
Basically this acts like a DB data audit trigger.
Doing this so we also track deletions, and not just insert/update.
"""
ident = models.SmallIntegerField(default=1, primary_key=True, unique=True)
last_update = models.DateTimeField(null=False)
class Meta:
verbose_name = _('periodic task track')
verbose_name_plural = _('periodic task tracks')
@classmethod
def changed(cls, instance, **kwargs):
if not instance.no_changes:
cls.update_changed()
@classmethod
def update_changed(cls, **kwargs):
cls.objects.update_or_create(ident=1, defaults={'last_update': now()})
@classmethod
def last_change(cls):
try:
return cls.objects.get(ident=1).last_update
except cls.DoesNotExist:
pass
class PeriodicTask(models.Model):
"""Model representing a periodic task."""
name = models.CharField(
max_length=200, unique=True,
verbose_name=_('Name'),
help_text=_('Short Description For This Task'),
)
task = models.CharField(
max_length=200,
verbose_name='Task Name',
help_text=_('The Name of the Celery Task that Should be Run. '
'(Example: "proj.tasks.import_contacts")'),
)
# You can only set ONE of the following schedule FK's
# TODO: Redo this as a GenericForeignKey
interval = models.ForeignKey(
IntervalSchedule, on_delete=models.CASCADE,
null=True, blank=True, verbose_name=_('Interval Schedule'),
help_text=_('Interval Schedule to run the task on. '
'Set only one schedule type, leave the others null.'),
)
crontab = models.ForeignKey(
CrontabSchedule, on_delete=models.CASCADE, null=True, blank=True,
verbose_name=_('Crontab Schedule'),
help_text=_('Crontab Schedule to run the task on. '
'Set only one schedule type, leave the others null.'),
)
solar = models.ForeignKey(
SolarSchedule, on_delete=models.CASCADE, null=True, blank=True,
verbose_name=_('Solar Schedule'),
help_text=_('Solar Schedule to run the task on. '
'Set only one schedule type, leave the others null.'),
)
clocked = models.ForeignKey(
ClockedSchedule, on_delete=models.CASCADE, null=True, blank=True,
verbose_name=_('Clocked Schedule'),
help_text=_('Clocked Schedule to run the task on. '
'Set only one schedule type, leave the others null.'),
)
# TODO: use django's JsonField
args = models.TextField(
blank=True, default='[]',
verbose_name=_('Positional Arguments'),
help_text=_(
'JSON encoded positional arguments '
'(Example: ["arg1", "arg2"])'),
)
kwargs = models.TextField(
blank=True, default='{}',
verbose_name=_('Keyword Arguments'),
help_text=_(
'JSON encoded keyword arguments '
'(Example: {"argument": "value"})'),
)
queue = models.CharField(
max_length=200, blank=True, null=True, default=None,
verbose_name=_('Queue Override'),
help_text=_(
'Queue defined in CELERY_TASK_QUEUES. '
'Leave None for default queuing.'),
)
# you can use low-level AMQP routing options here,
# but you almost certaily want to leave these as None
# http://docs.celeryproject.org/en/latest/userguide/routing.html#exchanges-queues-and-routing-keys
exchange = models.CharField(
max_length=200, blank=True, null=True, default=None,
verbose_name=_('Exchange'),
help_text=_('Override Exchange for low-level AMQP routing'),
)
routing_key = models.CharField(
max_length=200, blank=True, null=True, default=None,
verbose_name=_('Routing Key'),
help_text=_('Override Routing Key for low-level AMQP routing'),
)
headers = models.TextField(
blank=True, default='{}',
verbose_name=_('AMQP Message Headers'),
help_text=_('JSON encoded message headers for the AMQP message.'),
)
priority = models.PositiveIntegerField(
default=None, validators=[MaxValueValidator(255)],
blank=True, null=True,
verbose_name=_('Priority'),
help_text=_(
'Priority Number between 0 and 255. '
'Supported by: RabbitMQ, Redis (priority reversed, 0 is highest).')
)
expires = models.DateTimeField(
blank=True, null=True,
verbose_name=_('Expires Datetime'),
help_text=_(
'Datetime after which the schedule will no longer '
'trigger the task to run'),
)
expire_seconds = models.PositiveIntegerField(
blank=True, null=True,
verbose_name=_('Expires timedelta with seconds'),
help_text=_(
'Timedelta with seconds which the schedule will no longer '
'trigger the task to run'),
)
one_off = models.BooleanField(
default=False,
verbose_name=_('One-off Task'),
help_text=_(
'If True, the schedule will only run the task a single time'),
)
start_time = models.DateTimeField(
blank=True, null=True,
verbose_name=_('Start Datetime'),
help_text=_(
'Datetime when the schedule should begin '
'triggering the task to run'),
)
enabled = models.BooleanField(
default=True,
verbose_name=_('Enabled'),
help_text=_('Set to False to disable the schedule'),
)
last_run_at = models.DateTimeField(
auto_now=False, auto_now_add=False,
editable=False, blank=True, null=True,
verbose_name=_('Last Run Datetime'),
help_text=_(
'Datetime that the schedule last triggered the task to run. '
'Reset to None if enabled is set to False.'),
)
total_run_count = models.PositiveIntegerField(
default=0, editable=False,
verbose_name=_('Total Run Count'),
help_text=_(
'Running count of how many times the schedule '
'has triggered the task'),
)
date_changed = models.DateTimeField(
auto_now=True,
verbose_name=_('Last Modified'),
help_text=_('Datetime that this PeriodicTask was last modified'),
)
description = models.TextField(
blank=True,
verbose_name=_('Description'),
help_text=_(
'Detailed description about the details of this Periodic Task'),
)
objects = querysets.PeriodicTaskQuerySet.as_manager()
no_changes = False
class Meta:
"""Table information."""
verbose_name = _('periodic task')
verbose_name_plural = _('periodic tasks')
def validate_unique(self, *args, **kwargs):
super().validate_unique(*args, **kwargs)
schedule_types = ['interval', 'crontab', 'solar', 'clocked']
selected_schedule_types = [s for s in schedule_types
if getattr(self, s)]
if len(selected_schedule_types) == 0:
raise ValidationError(
'One of clocked, interval, crontab, or solar '
'must be set.'
)
err_msg = 'Only one of clocked, interval, crontab, '\
'or solar must be set'
if len(selected_schedule_types) > 1:
error_info = {}
for selected_schedule_type in selected_schedule_types:
error_info[selected_schedule_type] = [err_msg]
raise ValidationError(error_info)
# clocked must be one off task
if self.clocked and not self.one_off:
err_msg = 'clocked must be one off, one_off must set True'
raise ValidationError(err_msg)
def save(self, *args, **kwargs):
self.exchange = self.exchange or None
self.routing_key = self.routing_key or None
self.queue = self.queue or None
self.headers = self.headers or None
if not self.enabled:
self.last_run_at = None
self._clean_expires()
self.validate_unique()
super().save(*args, **kwargs)
PeriodicTasks.changed(self)
def delete(self, *args, **kwargs):
super().delete(*args, **kwargs)
PeriodicTasks.changed(self)
def _clean_expires(self):
if self.expire_seconds is not None and self.expires:
raise ValidationError(
_('Only one can be set, in expires and expire_seconds')
)
@property
def expires_(self):
return self.expires or self.expire_seconds
def __str__(self):
fmt = '{0.name}: {{no schedule}}'
if self.interval:
fmt = '{0.name}: {0.interval}'
if self.crontab:
fmt = '{0.name}: {0.crontab}'
if self.solar:
fmt = '{0.name}: {0.solar}'
if self.clocked:
fmt = '{0.name}: {0.clocked}'
return fmt.format(self)
@property
def scheduler(self):
if self.interval:
return self.interval
if self.crontab:
return self.crontab
if self.solar:
return self.solar
if self.clocked:
return self.clocked
@property
def schedule(self):
return self.scheduler.schedule
def due_start_time(self, tz):
if self.crontab:
return self.crontab.due_start_time(self.start_time, tz)
else:
return self.start_time

View File

@@ -0,0 +1,11 @@
"""Model querysets."""
from django.db import models
class PeriodicTaskQuerySet(models.QuerySet):
"""QuerySet for PeriodicTask."""
def enabled(self):
return self.filter(enabled=True).prefetch_related(
"interval", "crontab", "solar", "clocked"
)

View File

@@ -0,0 +1,540 @@
"""Beat Scheduler Implementation."""
import datetime
import logging
import math
from multiprocessing.util import Finalize
try:
from zoneinfo import ZoneInfo # Python 3.9+
except ImportError:
from backports.zoneinfo import ZoneInfo # Python 3.8
from celery import current_app, schedules
from celery.beat import ScheduleEntry, Scheduler
from celery.utils.log import get_logger
from celery.utils.time import maybe_make_aware
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.db import close_old_connections, transaction
from django.db.models import Case, F, IntegerField, Q, When
from django.db.models.functions import Cast
from django.db.utils import DatabaseError, InterfaceError
from kombu.utils.encoding import safe_repr, safe_str
from kombu.utils.json import dumps, loads
from .clockedschedule import clocked
from .models import (ClockedSchedule, CrontabSchedule, IntervalSchedule,
PeriodicTask, PeriodicTasks, SolarSchedule)
from .utils import NEVER_CHECK_TIMEOUT, aware_now, now
# This scheduler must wake up more frequently than the
# regular of 5 minutes because it needs to take external
# changes to the schedule into account.
DEFAULT_MAX_INTERVAL = 5 # seconds
SCHEDULE_SYNC_MAX_INTERVAL = 300 # 5 minutes
ADD_ENTRY_ERROR = """\
Cannot add entry %r to database schedule: %r. Contents: %r
"""
logger = get_logger(__name__)
debug, info, warning = logger.debug, logger.info, logger.warning
class ModelEntry(ScheduleEntry):
"""Scheduler entry taken from database row."""
model_schedules = (
(schedules.crontab, CrontabSchedule, 'crontab'),
(schedules.schedule, IntervalSchedule, 'interval'),
(schedules.solar, SolarSchedule, 'solar'),
(clocked, ClockedSchedule, 'clocked')
)
save_fields = ['last_run_at', 'total_run_count', 'no_changes']
def __init__(self, model, app=None):
"""Initialize the model entry."""
self.app = app or current_app._get_current_object()
self.name = model.name
self.task = model.task
try:
self.schedule = model.schedule
except model.DoesNotExist:
logger.error(
'Disabling schedule %s that was removed from database',
self.name,
)
self._disable(model)
try:
self.args = loads(model.args or '[]')
self.kwargs = loads(model.kwargs or '{}')
except ValueError as exc:
logger.exception(
'Removing schedule %s for argument deseralization error: %r',
self.name, exc,
)
self._disable(model)
self.options = {}
for option in ['queue', 'exchange', 'routing_key', 'priority']:
value = getattr(model, option)
if value is None:
continue
self.options[option] = value
if getattr(model, 'expires_', None):
self.options['expires'] = getattr(model, 'expires_')
headers = loads(model.headers or '{}')
headers['periodic_task_name'] = model.name
self.options['headers'] = headers
self.total_run_count = model.total_run_count
self.model = model
if not model.last_run_at:
model.last_run_at = model.date_changed or self._default_now()
# if last_run_at is not set and
# model.start_time last_run_at should be in way past.
# This will trigger the job to run at start_time
# and avoid the heap block.
if self.model.start_time:
model.last_run_at = model.last_run_at \
- datetime.timedelta(days=365 * 30)
self.last_run_at = model.last_run_at
def _disable(self, model):
model.no_changes = True
model.enabled = False
model.save()
def is_due(self):
if not self.model.enabled:
# 5 second delay for re-enable.
return schedules.schedstate(False, 5.0)
# START DATE: only run after the `start_time`, if one exists.
if self.model.start_time is not None:
now = self._default_now()
if getattr(settings, 'DJANGO_CELERY_BEAT_TZ_AWARE', True):
now = maybe_make_aware(self._default_now())
if now < self.model.start_time:
# The datetime is before the start date - don't run.
# send a delay to retry on start_time
current_tz = now.tzinfo
start_time = self.model.due_start_time(current_tz)
time_remaining = start_time - now
delay = math.ceil(time_remaining.total_seconds())
return schedules.schedstate(False, delay)
# EXPIRED TASK: Disable task when expired
if self.model.expires is not None:
now = self._default_now()
if now >= self.model.expires:
self._disable(self.model)
# Don't recheck
return schedules.schedstate(False, NEVER_CHECK_TIMEOUT)
# ONE OFF TASK: Disable one off tasks after they've ran once
if self.model.one_off and self.model.enabled \
and self.model.total_run_count > 0:
self.model.enabled = False
self.model.total_run_count = 0 # Reset
self.model.no_changes = False # Mark the model entry as changed
self.model.save()
# Don't recheck
return schedules.schedstate(False, NEVER_CHECK_TIMEOUT)
# CAUTION: make_aware assumes settings.TIME_ZONE for naive datetimes,
# while maybe_make_aware assumes utc for naive datetimes
tz = self.app.timezone
last_run_at_in_tz = maybe_make_aware(self.last_run_at).astimezone(tz)
return self.schedule.is_due(last_run_at_in_tz)
def _default_now(self):
if getattr(settings, 'DJANGO_CELERY_BEAT_TZ_AWARE', True):
now = datetime.datetime.now(self.app.timezone)
else:
# this ends up getting passed to maybe_make_aware, which expects
# all naive datetime objects to be in utc time.
now = datetime.datetime.utcnow()
return now
def __next__(self):
self.model.last_run_at = self._default_now()
self.model.total_run_count += 1
self.model.no_changes = True
return self.__class__(self.model)
next = __next__ # for 2to3
def save(self):
# Object may not be synchronized, so only
# change the fields we care about.
obj = type(self.model)._default_manager.get(pk=self.model.pk)
for field in self.save_fields:
setattr(obj, field, getattr(self.model, field))
obj.save()
@classmethod
def to_model_schedule(cls, schedule):
for schedule_type, model_type, model_field in cls.model_schedules:
schedule = schedules.maybe_schedule(schedule)
if isinstance(schedule, schedule_type):
model_schedule = model_type.from_schedule(schedule)
model_schedule.save()
return model_schedule, model_field
raise ValueError(
f'Cannot convert schedule type {schedule!r} to model')
@classmethod
def from_entry(cls, name, app=None, **entry):
obj, created = PeriodicTask._default_manager.update_or_create(
name=name, defaults=cls._unpack_fields(**entry),
)
return cls(obj, app=app)
@classmethod
def _unpack_fields(cls, schedule,
args=None, kwargs=None, relative=None, options=None,
**entry):
entry_schedules = {
model_field: None for _, _, model_field in cls.model_schedules
}
model_schedule, model_field = cls.to_model_schedule(schedule)
entry_schedules[model_field] = model_schedule
entry.update(
entry_schedules,
args=dumps(args or []),
kwargs=dumps(kwargs or {}),
**cls._unpack_options(**options or {})
)
return entry
@classmethod
def _unpack_options(cls, queue=None, exchange=None, routing_key=None,
priority=None, headers=None, expire_seconds=None,
**kwargs):
return {
'queue': queue,
'exchange': exchange,
'routing_key': routing_key,
'priority': priority,
'headers': dumps(headers or {}),
'expire_seconds': expire_seconds,
}
def __repr__(self):
return '<ModelEntry: {} {}(*{}, **{}) {}>'.format(
safe_str(self.name), self.task, safe_repr(self.args),
safe_repr(self.kwargs), self.schedule,
)
class DatabaseScheduler(Scheduler):
"""Database-backed Beat Scheduler."""
Entry = ModelEntry
Model = PeriodicTask
Changes = PeriodicTasks
_schedule = None
_last_timestamp = None
_initial_read = True
_heap_invalidated = False
_last_full_sync = None
def __init__(self, *args, **kwargs):
"""Initialize the database scheduler."""
self._dirty = set()
Scheduler.__init__(self, *args, **kwargs)
self._finalize = Finalize(self, self.sync, exitpriority=5)
self.max_interval = (
kwargs.get('max_interval')
or self.app.conf.beat_max_loop_interval
or DEFAULT_MAX_INTERVAL)
def setup_schedule(self):
self.install_default_entries(self.schedule)
self.update_from_dict(self.app.conf.beat_schedule)
def all_as_schedule(self):
debug('DatabaseScheduler: Fetching database schedule')
s = {}
for model in self.enabled_models():
try:
s[model.name] = self.Entry(model, app=self.app)
except ValueError:
pass
return s
def enabled_models(self):
"""Return list of enabled periodic tasks.
Allows overriding how the list of periodic tasks is fetched without
duplicating the filtering/querying logic.
"""
return list(self.enabled_models_qs())
def enabled_models_qs(self):
next_schedule_sync = now() + datetime.timedelta(
seconds=SCHEDULE_SYNC_MAX_INTERVAL
)
exclude_clock_tasks_query = Q(
clocked__isnull=False,
clocked__clocked_time__gt=next_schedule_sync
)
exclude_cron_tasks_query = self._get_crontab_exclude_query()
# Combine the queries for optimal database filtering
exclude_query = exclude_clock_tasks_query | exclude_cron_tasks_query
# Fetch only the tasks we need to consider
return self.Model.objects.enabled().exclude(exclude_query)
def _get_crontab_exclude_query(self):
"""
Build a query to exclude crontab tasks based on their hour value,
adjusted for timezone differences relative to the server.
This creates an annotation for each crontab task that represents the
server-equivalent hour, then filters on that annotation.
"""
# Get server time based on Django settings
server_time = aware_now()
server_hour = server_time.hour
# Window of +/- 2 hours around the current hour in server tz.
hours_to_include = [
(server_hour + offset) % 24 for offset in range(-2, 3)
]
hours_to_include += [4] # celery's default cleanup task
# Regex pattern to match only numbers
# This ensures we only process numeric hour values
numeric_hour_pattern = r'^\d+$'
# Get all tasks with a simple numeric hour value
numeric_hour_tasks = CrontabSchedule.objects.filter(
hour__regex=numeric_hour_pattern
)
# Annotate these tasks with their server-hour equivalent
annotated_tasks = numeric_hour_tasks.annotate(
# Cast hour string to integer
hour_int=Cast('hour', IntegerField()),
# Calculate server-hour based on timezone offset
server_hour=Case(
# Handle each timezone specifically
*[
When(
timezone=timezone_name,
then=(
F('hour_int')
+ self._get_timezone_offset(timezone_name)
+ 24
) % 24
)
for timezone_name in self._get_unique_timezone_names()
],
# Default case - use hour as is
default=F('hour_int')
)
)
excluded_hour_task_ids = annotated_tasks.exclude(
server_hour__in=hours_to_include
).values_list('id', flat=True)
# Build the final exclude query:
# Exclude crontab tasks that are not in our include list
exclude_query = Q(crontab__isnull=False) & Q(
crontab__id__in=excluded_hour_task_ids
)
return exclude_query
def _get_unique_timezone_names(self):
"""Get a list of all unique timezone names used in CrontabSchedule"""
return CrontabSchedule.objects.values_list(
'timezone', flat=True
).distinct()
def _get_timezone_offset(self, timezone_name):
"""
Args:
timezone_name: The name of the timezone or a ZoneInfo object
Returns:
int: The hour offset
"""
# Get server timezone
server_time = aware_now()
# Use server_time.tzinfo directly if it is already a ZoneInfo instance
if isinstance(server_time.tzinfo, ZoneInfo):
server_tz = server_time.tzinfo
else:
server_tz = ZoneInfo(str(server_time.tzinfo))
if isinstance(timezone_name, ZoneInfo):
timezone_name = timezone_name.key
target_tz = ZoneInfo(timezone_name)
# Use a fixed point in time for the calculation to avoid DST issues
fixed_dt = datetime.datetime(2023, 1, 1, 12, 0, 0)
# Calculate the offset
dt1 = fixed_dt.replace(tzinfo=server_tz)
dt2 = fixed_dt.replace(tzinfo=target_tz)
# Calculate hour difference
offset_seconds = (
dt1.utcoffset().total_seconds() - dt2.utcoffset().total_seconds()
)
offset_hours = int(offset_seconds / 3600)
return offset_hours
def schedule_changed(self):
try:
close_old_connections()
# If MySQL is running with transaction isolation level
# REPEATABLE-READ (default), then we won't see changes done by
# other transactions until the current transaction is
# committed (Issue #41).
try:
transaction.commit()
except transaction.TransactionManagementError:
pass # not in transaction management.
last, ts = self._last_timestamp, self.Changes.last_change()
except DatabaseError as exc:
logger.exception('Database gave error: %r', exc)
return False
except InterfaceError:
warning(
'DatabaseScheduler: InterfaceError in schedule_changed(), '
'waiting to retry in next call...'
)
return False
try:
if ts and ts > (last if last else ts):
return True
finally:
self._last_timestamp = ts
return False
def reserve(self, entry):
new_entry = next(entry)
# Need to store entry by name, because the entry may change
# in the mean time.
self._dirty.add(new_entry.name)
return new_entry
def sync(self):
if logger.isEnabledFor(logging.DEBUG):
debug('Writing entries...')
_tried = set()
_failed = set()
try:
close_old_connections()
while self._dirty:
name = self._dirty.pop()
try:
self._schedule[name].save()
_tried.add(name)
except (KeyError, TypeError, ObjectDoesNotExist):
_failed.add(name)
except DatabaseError as exc:
logger.exception('Database error while sync: %r', exc)
except InterfaceError:
warning(
'DatabaseScheduler: InterfaceError in sync(), '
'waiting to retry in next call...'
)
finally:
# retry later, only for the failed ones
self._dirty |= _failed
def update_from_dict(self, mapping):
s = {}
for name, entry_fields in mapping.items():
try:
entry = self.Entry.from_entry(name,
app=self.app,
**entry_fields)
if entry.model.enabled:
s[name] = entry
except Exception as exc:
logger.exception(ADD_ENTRY_ERROR, name, exc, entry_fields)
self.schedule.update(s)
def install_default_entries(self, data):
entries = {}
if self.app.conf.result_expires:
entries.setdefault(
'celery.backend_cleanup', {
'task': 'celery.backend_cleanup',
'schedule': schedules.crontab('0', '4', '*'),
'options': {'expire_seconds': 12 * 3600},
},
)
self.update_from_dict(entries)
def schedules_equal(self, *args, **kwargs):
if self._heap_invalidated:
self._heap_invalidated = False
return False
return super().schedules_equal(*args, **kwargs)
@property
def schedule(self):
initial = update = False
current_time = datetime.datetime.now()
if self._initial_read:
debug('DatabaseScheduler: initial read')
initial = update = True
self._initial_read = False
self._last_full_sync = current_time
elif self.schedule_changed():
info('DatabaseScheduler: Schedule changed.')
update = True
self._last_full_sync = current_time
# Force update the schedule if it's been more than 5 minutes
if not update:
time_since_last_sync = (
current_time - self._last_full_sync
).total_seconds()
if (
time_since_last_sync >= SCHEDULE_SYNC_MAX_INTERVAL
):
debug(
'DatabaseScheduler: Forcing full sync after 5 minutes'
)
update = True
self._last_full_sync = current_time
if update:
self.sync()
self._schedule = self.all_as_schedule()
# the schedule changed, invalidate the heap in Scheduler.tick
if not initial:
self._heap = []
self._heap_invalidated = True
if logger.isEnabledFor(logging.DEBUG):
debug('Current schedule:\n%s', '\n'.join(
repr(entry) for entry in self._schedule.values()),
)
return self._schedule

View File

@@ -0,0 +1,44 @@
"""Django Application signals."""
def signals_connect():
"""Connect to signals."""
from django.db.models import signals
from .models import (ClockedSchedule, CrontabSchedule, IntervalSchedule,
PeriodicTask, PeriodicTasks, SolarSchedule)
signals.pre_save.connect(
PeriodicTasks.changed, sender=PeriodicTask
)
signals.pre_delete.connect(
PeriodicTasks.changed, sender=PeriodicTask
)
signals.post_save.connect(
PeriodicTasks.update_changed, sender=IntervalSchedule
)
signals.pre_delete.connect(
PeriodicTasks.update_changed, sender=IntervalSchedule
)
signals.post_save.connect(
PeriodicTasks.update_changed, sender=CrontabSchedule
)
signals.post_delete.connect(
PeriodicTasks.update_changed, sender=CrontabSchedule
)
signals.post_save.connect(
PeriodicTasks.update_changed, sender=SolarSchedule
)
signals.post_delete.connect(
PeriodicTasks.update_changed, sender=SolarSchedule
)
signals.post_save.connect(
PeriodicTasks.update_changed, sender=ClockedSchedule
)
signals.post_delete.connect(
PeriodicTasks.update_changed, sender=ClockedSchedule
)

View File

@@ -0,0 +1,20 @@
{% extends "admin/change_list.html" %}
{% load i18n %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=cl.opts.app_label %}">{{ cl.opts.app_config.verbose_name }}</a>
&rsaquo; {{ cl.opts.verbose_name_plural|capfirst }}
</div>
{% if wrong_scheduler %}
<ul class="messagelist">
<li class="warning">
Periodic tasks won't be dispatched unless you set the
<code>CELERY_BEAT_SCHEDULER</code> setting to
<code>djcelery.schedulers.DatabaseScheduler</code>,
or specify it using the <code>-S</code> option to celerybeat
</li>
</ul>
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,22 @@
{% extends 'admin/change_form.html' %}
{% block admin_change_form_document_ready %}
{{ block.super }}
{{ readable_crontabs|json_script:"readable-crontabs" }}
<script id="periodic-task-overrides">
const readableCrontabs = JSON.parse(django.jQuery("#readable-crontabs").text());
var originalCrontabHelp = "{{ adminform.form.fields.crontab.help_text }}";
var updateCrontabHelp = function(additional) {
django.jQuery(".field-crontab .help").html(
`${originalCrontabHelp}<br/>Translation: ${additional}`);
};
django.jQuery(".field-crontab_translation").hide()
django.jQuery(".field-crontab").change(function() {
updateCrontabHelp(readableCrontabs[django.jQuery("#id_crontab").val()]);
});
</script>
{% endblock %}

View File

@@ -0,0 +1,72 @@
"""Timezone aware Cron schedule Implementation."""
from collections import namedtuple
from datetime import datetime, timezone
from celery import schedules
schedstate = namedtuple('schedstate', ('is_due', 'next'))
class TzAwareCrontab(schedules.crontab):
"""Timezone Aware Crontab."""
def __init__(
self, minute='*', hour='*', day_of_week='*',
day_of_month='*', month_of_year='*', tz=timezone.utc, app=None
):
"""Overwrite Crontab constructor to include a timezone argument."""
self.tz = tz
nowfun = self.nowfunc
super().__init__(
minute=minute, hour=hour, day_of_week=day_of_week,
day_of_month=day_of_month,
month_of_year=month_of_year, nowfun=nowfun, app=app
)
def nowfunc(self):
return datetime.now(self.tz)
def is_due(self, last_run_at):
"""Calculate when the next run will take place.
Return tuple of ``(is_due, next_time_to_check)``.
The ``last_run_at`` argument needs to be timezone aware.
"""
# convert last_run_at to the schedule timezone
last_run_at = last_run_at.astimezone(self.tz)
rem_delta = self.remaining_estimate(last_run_at)
rem = max(rem_delta.total_seconds(), 0)
due = rem == 0
if due:
rem_delta = self.remaining_estimate(self.now())
rem = max(rem_delta.total_seconds(), 0)
return schedstate(due, rem)
# Needed to support pickling
def __repr__(self):
return """<crontab: {0._orig_minute} {0._orig_hour}
{0._orig_day_of_week} {0._orig_day_of_month}
{0._orig_month_of_year} (m/h/d/dM/MY), {0.tz}>
""".format(self)
def __reduce__(self):
return (self.__class__, (self._orig_minute,
self._orig_hour,
self._orig_day_of_week,
self._orig_day_of_month,
self._orig_month_of_year,
self.tz), None)
def __eq__(self, other):
if isinstance(other, schedules.crontab):
return (other.month_of_year == self.month_of_year
and other.day_of_month == self.day_of_month
and other.day_of_week == self.day_of_week
and other.hour == self.hour
and other.minute == self.minute
and other.tz == self.tz)
return NotImplemented

View File

@@ -0,0 +1,66 @@
"""Utilities."""
import datetime
# -- XXX This module must not use translation as that causes
# -- a recursive loader import!
from datetime import timezone as datetime_timezone
try:
from zoneinfo import ZoneInfo # Python 3.9+
except ImportError:
from backports.zoneinfo import ZoneInfo # Python 3.8
from django.conf import settings
from django.utils import timezone
is_aware = timezone.is_aware
# celery schedstate return None will make it not work
NEVER_CHECK_TIMEOUT = 100000000
# see Issue #222
now_localtime = getattr(timezone, 'template_localtime', timezone.localtime)
def make_aware(value):
"""Force datatime to have timezone information."""
if getattr(settings, 'USE_TZ', False):
# naive datetimes are assumed to be in UTC.
if timezone.is_naive(value):
value = timezone.make_aware(value, datetime_timezone.utc)
# then convert to the Django configured timezone.
default_tz = timezone.get_default_timezone()
value = timezone.localtime(value, default_tz)
elif timezone.is_naive(value):
# naive datetimes are assumed to be in local timezone.
value = timezone.make_aware(value, timezone.get_default_timezone())
return value
def now():
"""Return the current date and time."""
if getattr(settings, 'USE_TZ', False):
return now_localtime(timezone.now())
else:
return timezone.now()
def aware_now():
if getattr(settings, 'USE_TZ', True):
# When USE_TZ is True, return timezone.now()
return timezone.now()
else:
# When USE_TZ is False, use the project's timezone
project_tz = ZoneInfo(getattr(settings, 'TIME_ZONE', 'UTC'))
return datetime.datetime.now(project_tz)
def is_database_scheduler(scheduler):
"""Return true if Celery is configured to use the db scheduler."""
if not scheduler:
return False
from kombu.utils import symbol_by_name
from .schedulers import DatabaseScheduler
return (
scheduler == 'django'
or issubclass(symbol_by_name(scheduler), DatabaseScheduler)
)

View File

@@ -0,0 +1,106 @@
"""Validators."""
import crontab
from django.core.exceptions import ValidationError
class _CronSlices(crontab.CronSlices):
"""Cron slices with customized validation."""
def __init__(self, *args):
super(crontab.CronSlices, self).__init__(
[_CronSlice(info) for info in crontab.S_INFO]
)
self.special = None
self.setall(*args)
self.is_valid = self.is_self_valid
@classmethod
def validate(cls, *args):
try:
cls(*args)
except Exception as e:
raise ValueError(e)
class _CronSlice(crontab.CronSlice):
"""Cron slice with custom range parser."""
def get_range(self, *vrange):
ret = _CronRange(self, *vrange)
if ret.dangling is not None:
return [ret.dangling, ret]
return [ret]
class _CronRange(crontab.CronRange):
"""Cron range parser class."""
# rewrite whole method to raise error on bad range
def parse(self, value):
if value.count('/') == 1:
value, seq = value.split('/')
try:
self.seq = self.slice.parse_value(seq)
except crontab.SundayError:
self.seq = 1
value = "0-0"
if self.seq < 1 or self.seq > self.slice.max:
raise ValueError("Sequence can not be divided by zero or max")
if value.count('-') == 1:
vfrom, vto = value.split('-')
self.vfrom = self.slice.parse_value(vfrom, sunday=0)
try:
self.vto = self.slice.parse_value(vto)
except crontab.SundayError:
if self.vfrom == 1:
self.vfrom = 0
else:
self.dangling = 0
self.vto = self.slice.parse_value(vto, sunday=6)
if self.vto < self.vfrom:
raise ValueError("Bad range '{0.vfrom}-{0.vto}'".format(self))
elif value == '*':
self.all()
else:
raise ValueError('Unknown cron range value "%s"' % value)
def crontab_validator(value):
"""Validate crontab."""
try:
_CronSlices.validate(value)
except ValueError as e:
raise ValidationError(e)
def minute_validator(value):
"""Validate minutes crontab value."""
_validate_crontab(value, 0)
def hour_validator(value):
"""Validate hours crontab value."""
_validate_crontab(value, 1)
def day_of_month_validator(value):
"""Validate day of month crontab value."""
_validate_crontab(value, 2)
def month_of_year_validator(value):
"""Validate month crontab value."""
_validate_crontab(value, 3)
def day_of_week_validator(value):
"""Validate day of week crontab value."""
_validate_crontab(value, 4)
def _validate_crontab(value, index):
tab = ['*'] * 5
tab[index] = value
tab = ' '.join(tab)
crontab_validator(tab)