Creare un Task

Per aggiungere un task creare il file tasks.py

creare la classe in tasks.py:

class NomeTask(JmbJobtasticTask):
   task_name = "NOME DEL TASK" # qui mettere il nome del task
   def calculate_result(self, **kw):
       #qui mettere la logica del task
       pass

esempio:

class AspettaTask(JmbJobtasticTask):
   task_name = "NOME DEL TASK"
   significant_kwargs = []
   herd_avoidance_timeout = 60
   cache_duration = 0
   def calculate_result(self, **kw):
       logger.info('Running aspetta con xtastic ')

       n_of_steps = 20
       sec_for_step = 2
       # Only actually update the progress in the backend every n operations
       update_frequency = 1
       total_delay = 40

       for count, x in enumerate(range(0, total_delay, sec_for_step)):
           time.sleep(sec_for_step)
           self.update_progress(
               count,
               n_of_steps,
               update_frequency=update_frequency,
           )
           logger.info('Running aspetta - %s' % x)
       return "Finito!"

Se si vuole far partire il task dal menu admin della change_list, creare l’azione, importare la classe NomeTask dal file tasks.py e far chiamare NomeTask.delay_or_fail()

esempio:

from jmb.async.tasks import AspettaTask

class TaskAdmin(ExtendibleModelAdmin):

   def action_task(self, request, queryset):
           result = AspettaTask.delay_or_fail()
   actions = [action_task]

per provare un task di test, attivare il debug selezionare dell admin http://127.0.0.1:8000/admin/async/task/ un task e selezionare l’azione “Create task test”

Azione di django come task

Ecco un esempio completo di esportazione di dati in csv:

# coding: utf-8
import os
import logging

import unicodecsv as csv

from django.conf import settings
from django.http import HttpRequest
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
from django.contrib import admin

from jmb.core.admin.options import _export_data
from jmb.async.models import Task
from jmb.async.tasks import JmbJobtasticTask

logger = logging.getLogger('celery.task')


def export_csv_async(modeladmin, request, queryset):
    """
    action per esportazione elementi selezionati changelist_view in .csv in modo asincrono
    """
    GET = request.GET.copy()
    pks = request.POST.getlist('_selected_action')
    select_across = int(request.POST.get('select_across'))

    msg = _('The task has been queued: you can monitor progress <a href="%s">here<a>')
    messages.info(request, mark_safe(msg % reverse('admin:async_task_changelist')))
    res = ExportContactTaskCsv.delay_or_fail(
        app_label='contact', model=modeladmin.model,
        pks=pks, select_across=select_across, get=GET
    )

export_csv_async.short_description = _("Export csv async")


class ExportContactTaskCsv(JmbJobtasticTask):
    task_name = _("Esportazione contatti csv")
    significant_kwargs = []
    herd_avoidance_timeout = 60
    cache_duration = 0

    def calculate_result(self, model=None, pks=None, select_across=None, get=None):
        logger.info('Running ExportContact con xtastic')
        admin.autodiscover()
        modeladmin = admin.site._registry[model]
        if select_across:
            request = HttpRequest()
            request.GET = get
            qs = modeladmin.queryset(request)
            n_of_steps = qs.count()
        else:
            qs = modeladmin.model.objects.filter(id__in=pks)
            n_of_steps = len(pks)
        rows = []
        for count, row in enumerate(_export_data(modeladmin, queryset=qs)):
            rows += [row]
            self.update_progress(
                count,
                n_of_steps,
                update_frequency=100,
            )
        task_id = self.request.id
        output_filename = self.create_file(
            rows, output_filename=os.path.join(settings.MEDIA_ROOT, 'tasks', "%s.cvs" % task_id))
        task = Task.objects.get(task_id=task_id)
        msg = 'exported %s records' % count
        task.message = msg
        task.url = "tasks/%s.csv" % task_id
        task.save()
        return {'message': msg, 'url': output_filename}

    def create_file(self, rows, output_filename=None):
        with open(output_filename, 'wb') as writer:
            out = csv.writer(writer, delimiter=';',
                             quotechar='"', quoting=csv.QUOTE_ALL)
            out.writerows(rows)
        return output_filename

In questo caso si è tenuta l’azione assieme al task per chiarezza. Il queryset viene ricostruito nel task e viene gestito il fatto che sia stato selezionato il queryset completo o meno (select_across).

Nel task va personalizzato il metodo calculate_result: qui ricostruiamo La HttpResponse imponendo la GET serializzata e quindi ricostruiamo il queryset.

Sempre qui aggiorniamo il task con message e url che verrà servito da MEDIA_URL direttamente.

calculate_result ritorna un dizionario con:

message:il messaggio di fine lavoro (Es.: “Esportati 2345 contatti”)
url:l’eventuale file prodotto. Il download sarà fatto joinanndo questo con MEDIA_URL

Previous page

← Installazione

This Page