.. _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'