Files
django-q2/django_q/models.py
T
Ilan Steemers 44c8edb0a2 Keep task length on schedule for backward compatibility
Migrations on existing data would fail because of the old names being longer than the uuid. Keeping the field length at 100 will keep it compatible with existing  data.

Removed the squashed migrations cause this will cause dependency problems on existing installations. Every new migration will list the squashed migrations as a dependency. Not a problem for new installations, but will crash on exisitng ones.
2015-07-08 15:40:38 +02:00

150 lines
5.0 KiB
Python

import importlib
import logging
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from django.db import models
from django.db.models.signals import pre_save
from django.dispatch import receiver
from django.utils import timezone
from picklefield import PickledObjectField
class Task(models.Model):
id = models.CharField(max_length=32, primary_key=True, editable=False)
name = models.CharField(max_length=100, editable=False)
func = models.CharField(max_length=256)
hook = models.CharField(max_length=256, null=True)
args = PickledObjectField(null=True)
kwargs = PickledObjectField(null=True)
result = PickledObjectField(null=True)
started = models.DateTimeField(editable=False)
stopped = models.DateTimeField(editable=False)
success = models.BooleanField(default=True, editable=False)
@staticmethod
def get_result(task_id):
if len(task_id) == 32 and Task.objects.filter(id=task_id).exists():
return Task.objects.get(id=task_id).result
elif Task.objects.filter(name=task_id).exists():
return Task.objects.get(name=task_id).result
@staticmethod
def get_task(task_id):
if len(task_id) == 32 and Task.objects.filter(id=task_id).exists():
return Task.objects.get(id=task_id)
elif Task.objects.filter(name=task_id).exists():
return Task.objects.get(name=task_id)
def time_taken(self):
return (self.stopped - self.started).total_seconds()
def __unicode__(self):
return self.name
class Meta:
app_label = 'django_q'
@receiver(pre_save, sender=Task)
def call_hook(sender, instance, **kwargs):
if instance.hook:
logger = logging.getLogger('django-q')
f = instance.hook
if not callable(f):
try:
module, func = f.rsplit('.', 1)
m = importlib.import_module(module)
f = getattr(m, func)
except (ValueError, ImportError, AttributeError):
logger.error(_('malformed return hook \'{}\' for [{}]').format(instance.hook, instance.name))
return
try:
f(instance)
except Exception as e:
logger.error(_('return hook {} failed on [{}] because {}').format(instance.hook, instance.name, e))
class SuccessManager(models.Manager):
def get_queryset(self):
return super(SuccessManager, self).get_queryset().filter(
success=True)
class Success(Task):
objects = SuccessManager()
class Meta:
app_label = 'django_q'
verbose_name = _('Successful task')
verbose_name_plural = _('Successful tasks')
proxy = True
class FailureManager(models.Manager):
def get_queryset(self):
return super(FailureManager, self).get_queryset().filter(
success=False)
class Failure(Task):
objects = FailureManager()
class Meta:
app_label = 'django_q'
verbose_name = _('Failed task')
verbose_name_plural = _('Failed tasks')
proxy = True
class Schedule(models.Model):
func = models.CharField(max_length=256, help_text='e.g. module.tasks.function')
hook = models.CharField(max_length=256, null=True, blank=True, help_text='e.g. module.tasks.result_function')
args = models.TextField(null=True, blank=True, help_text=_("e.g. 1, 2, 'John'"))
kwargs = models.TextField(null=True, blank=True, help_text=_("e.g. x=1, y=2, name='John'"))
ONCE = 'O'
HOURLY = 'H'
DAILY = 'D'
WEEKLY = 'W'
MONTHLY = 'M'
QUARTERLY = 'Q'
YEARLY = 'Y'
TYPE = (
(ONCE, _('Once')),
(HOURLY, _('Hourly')),
(DAILY, _('Daily')),
(WEEKLY, _('Weekly')),
(MONTHLY, _('Monthly')),
(QUARTERLY, _('Quarterly')),
(YEARLY, _('Yearly')),
)
schedule_type = models.CharField(max_length=1, choices=TYPE, default=TYPE[0][0], verbose_name=_('Schedule Type'))
repeats = models.SmallIntegerField(default=-1, verbose_name=_('Repeats'), help_text=_('n = n times, -1 = forever'))
next_run = models.DateTimeField(verbose_name=_('Next Run'), default=timezone.now, null=True)
task = models.CharField(max_length=100, null=True, editable=False)
def success(self):
if self.task and Task.objects.filter(id=self.task):
return Task.objects.get(id=self.task).success
def last_run(self):
if self.task and Task.objects.filter(id=self.task):
task = Task.objects.get(id=self.task)
if task.success:
url = reverse('admin:django_q_success_change', args=(task.id,))
else:
url = reverse('admin:django_q_failure_change', args=(task.id,))
return '<a href="{}">[{}]</a>'.format(url, self.task)
return None
def __unicode__(self):
return self.func
success.boolean = True
class Meta:
app_label = 'django_q'
verbose_name = _('Scheduled task')
verbose_name_plural = _('Scheduled tasks')
ordering = ['next_run']