.. _tasks: ======================= Creare un Task ======================= .. automodule:: jmb.async.tasks Per aggiungere un task creare il file :file:`tasks.py` creare la classe in :file:`tasks.py`: .. code-block:: python 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 :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: .. code-block:: python # 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 here') 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`` .. _message-links: Link per messaggi ================= .. note:: viene creato un messaggio con il link all' ``admin/async/tasks/`` per monitorare i progressi del processo. Per fare in modo che questo link venga visualizzato correttamente occorre impostare:: MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'