How to use Django admin to create custom tasks using Celery

Viewed 505

I have a Django backend that I've created for a real estate company. I've built quite a few tasks that are hardcoded and I'm wanting to make those tasks customizable via the admin page... but I can't quite figure out how to do that.

For example, let's say that I wanted to create a task that would send an email that could be customized from the admin page. Ideally, I'd have a list of triggers to choose from like a contact form submission.

Something that looked like this:

enter image description here

1 Answers

I had the very same need on many occasions, and solved it as follows:

  1. I have an abstract "base" Task model with a few fields common to any "generic" background task: created_on, started_on, completed_on, status, progress, failure_reason and a few more
  2. When a new specific task is needed, I write:
    • a job function to be run by the scheduler (Celery in your case)
    • a concrete Model derived from Task
  3. The derived Model knows which job has to be run; this is hardcoded in the Model definition; I also add specific fields to collect any custom parameter required by the job
  4. Now, you can create a new task either programmatically or from the Django admin, supplying actual parameters as needed; in the latter case, Django provides the required form and validation as usual

After saving the new record in the database, the model kicks off the job, passing by the task (model) id; from the job you can retrieve task's details: which is the answer to the original question. You can also update the progress/status in the model for later inspection, and use other services provided by the base class (for example, logging).

This schema has been proven very useful, since, as an added benefit, you can monitor async tasks from the Django admin.

Having used it in several projects, I encapsulated this logic in a reusable Django app:

https://github.com/morlandi/django-task

The current implementation is based on rq, as Celery is over-engineered for my needs. I guess it can be adapted to Celery with some modifications:

  • remove Task.check_worker_active_for_queue()
  • remove Task.get_queue()
  • refactor Task.run()

Additionally, the helper Job class must be refactored as follows:

  • replace rq.get_current_job() with the equivalent for Celery

Unfortunately, I haven't used Celery recently, so I can't give more detailed advices.

Related