Here is part two. Let’s make an interface to see what’s going with Celery on right now.
Previous part: Part 1 🥩 Django steak medium rare
Next part: Part 3 🥄 Testing the taste
Following stack: Django + Celery + Nginx
Project structure
proj
proj
__init__.py
settings.py
urls.py
...
celery.py
firstapp
tasks.py
Content table
🍜 Cooking project dinner
- 🥩 Django steak medium rare
- 🥗 Broker salad
- 🥬 Chopped Redis
- 🥕 Carrot for Rabbitmq
- 🥒 Pickled tasks
- 🥗 Broker salad
- 🍮 Results pudding
- 🍪 HTML
- 🍯 View
- 🍫 Url
- 🥄 Testing the taste
- 🍻 Serving Celery workers
- 🍱 Pack Linux with Celery Daemon
🍜 Cooking project dinner
🍮 2. Results pudding
The django-celery-results package mentioned in Celery Docs does not work with Redis, so I will make a view with my own table of tasks.
2.1 HTML
I am using the Django admin base located at admin/
so my results/redis.html
has the following content (I also took code for tabs from W3School.com and modified it to fit my needs):
There are CSS for table and tabs, JS for tabs and HTML for a table. If there is something in the tab to show, it is green, otherwise grey and disabled. I tested it just a bit, I will return to it later, at the moment I don’t really need it as much.
But you, folks, go ahead and use it to build your own cool interface, if you want to.
It looks like this:

{% extends 'admin/base.html' %}
{% block content_title %}{{ title }}{% endblock content_title %}
{% block content %}
<br>{% for x in test %}{{ x }}<br>{% endfor %}
<style>/* Style the tab */
.tab {
overflow: hidden;
border: 1px solid #ccc;
background-color: #f1f1f1;
}
.tab button {
background-color: inherit;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 14px 16px;
transition: 0.3s;
}
.tab button.active {
background-color: #ccc;
}
.tabcontent {
display: none;
padding: 6px 12px;
border: 1px solid #ccc;
border-top: none;
}
th {
font-size: 20px;
font-weight: 400;
padding: 7px 15px;
border-right: 1px black solid;
line-height: 20px;
}
</style>
<script>function openCity(evt, cityName) {
// Declare all variables
var i, tabcontent, tablinks;
// Get all elements with class="tabcontent" and hide them
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
// Get all elements with class="tablinks" and remove the class "active"
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
// Show the current tab, and add an "active" class to the button that opened the tab
document.getElementById(cityName).style.display = "block";
evt.currentTarget.className += " active";
}</script>
<div class="tab" style="margin-top: 1%;">
<button class="tablinks" style="{% if results %}background: lightgreen;"{% else %}cursor:
default;" disabled{% endif %}
onclick="openCity(event, 'results')">Results
</button>
<button class="tablinks" style="{% if active_queues %}background: lightgreen;"{% else %}cursor:
default;" disabled{% endif %}
onclick="openCity(event, 'active_queues')">Active queues
</button>
<button class="tablinks" style="{% if active_tasks %}background: lightgreen;"{% else %}cursor:
default;" disabled{% endif %}
onclick="openCity(event, 'active_tasks')">Active tasks
</button>
<button class="tablinks" style="{% if reserved_tasks %}background: lightgreen;"{% else %}cursor:
default;" disabled{% endif %}
onclick="openCity(event, 'reserved_tasks')">Reserved tasks
</button>
<button class="tablinks" style="{% if scheduled_tasks %}background: lightgreen;"{% else %}cursor:
default;" disabled{% endif %}
onclick="openCity(event, 'scheduled_tasks')">Scheduled tasks
</button>
</div>
<!-- Tab content --><br>
<div id="results" class="tabcontent">
<h3>Results</h3>
{% if test %}
<table>
<tr style="border-bottom: 2px solid black;">
<th>Arguments</th>
<th>Results</th>
</tr>
{% for x in test %}
{% for y in x %}
<tr>
<th>{{ y }}</th>
<th></th>
</tr>
{% endfor %}
{% endfor %}
</table>
{% else %}No results{% endif %}
</div>
<div id="active_queues" class="tabcontent">
<h3>Active queues</h3>
{% if active_queues %}
{# {{ active_queues }}#}
<table>{% for x in active_queues %}
<tr>
<th>{{ key }}</th>
<th>{{ value }}</th>
</tr>{% endfor %}</table>
{% else %}No results{% endif %}
</div>
<div id="active_tasks" class="tabcontent">
<h3>Active tasks</h3>
{% if active_tasks %}
{% for x in active_tasks %}
{% for key, value in x %}
{{ key }}: {{ value }}<br>
{% endfor %}
<br>
{% endfor %}
{% else %}<p>No active tasks</p>{% endif %}
</div>
<div id="reserved_tasks" class="tabcontent">
<h3>Reserved tasks</h3>
{% if reserved_tasks %}
{% for x in active_tasks %}
{% for key, value in x %}
{{ key }}: {{ value }}<br>
{% endfor %}
<br>
{% endfor %}
{% else %}<p>No active tasks</p>{% endif %}
</div>
<div id="scheduled_tasks" class="tabcontent">
<h3>Scheduled tasks</h3>
{% if scheduled_tasks %}
{% for x in active_tasks %}
{% for key, value in x %}
{{ key }}: {{ value }}<br>
{% endfor %}
<br>
{% endfor %}
{% else %}<p>No active tasks</p>{% endif %}
</div>
{% endblock content %}
2.2 View
The view for the results can be located anywhere.
Default method is:
from django.views.generic.base import TemplateView
from firstapp.tasks import app
from celery.result import AsyncResult
import json, redis
class RedisResults(TemplateView):
template_name = 'results/redis.html'
def get_context_data(self, **kwargs):
context = super(RedisResults, self).get_context_data(**kwargs)
context['title'] = 'Redis Results'
r = redis.Redis("localhost", 6379)
t = r.keys(pattern="celery-task-meta*")
test = []
for x in t:
basic = AsyncResult(json.loads(r.get(x).decode('utf-8'))['task_id'], app=app).get()
if type(basic) != dict:
res = {'results': basic[1]}
basic = basic[0].update(res)
print(basic)
context['results'] = test
i = app.control.inspect()
context['bonus'] = i
try: context['active_queues'] = list(i.active_queues().values())[0][0].items()
except: pass
try: context['active_tasks'] = list(i.active().values())[0][0].items()
except: pass
try: context['reserved_tasks'] = list(i.reserved().values())[0][0].items()
except: pass
try: context['scheduled_tasks'] = list(i.scheduled().values())[0][0].items()
except: pass
return context
2.3 Url
To urlpatterns list add a new line:
path('results/redis/', celery_views.RedisResults.as_view(), name='results-redis')
Next part: Part 3 🥄 Testing the taste
[…] Next part: 🍮 Results pudding […]
LikeLike
[…] Previous part: Part 2 🍮 Results pudding […]
LikeLike