'How to send message to user in a Django Thread?

I have a long time execution function that I run in a Thread to avoid blocking the user during the process. But I have a problem when I want to notify the user at the end of this function to tell him that it's done (and tell him if it was a success or an error). I tried to use django.contrib.messages but unsuccessful. Here is my code simplified :

from threading import Thread 
from django.contrib import messages

def my_view(request):

    thread =Thread(target=run_creation, args=[request], daemon=True)
    thread.start()
    return render(request, 'main/home.html')

def run_creation(request):
    print("sleep start")
    time.sleep(20)
    print("sleep end")
    messages.add_message(request, messages.INFO, 'Hello word')

The problem is that I can't see the message in my template. Here is my template :

{% if messages %}
    <ul class="messages">
        {% for message in messages %}
            <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
        {% endfor %}
    </ul>
{% endif %}

Thanks a lot for your help



Solution 1:[1]

I managed to solve it - 7 elegant steps.

Steps do so:

  1. Install memcached as your cache backend.

    docker run -p 11211:11211 --name local-memcache -d memcached memcached -m 64

  2. Then go and pip install django-async-messages django-pymemcache

  3. Add this to your middleware in settings.py file:

    'async_messages.middleware.AsyncMiddleware'

Ensure it comes after 'django.contrib.messages.middleware.MessageMiddleware'

  1. Then add this to your settings.py file:

    CACHES = { 'default': { 'BACKEND': 'djpymemcache.backend.PyMemcacheCache', 'LOCATION': [ '127.0.0.1:11211', ], }, }

  2. Where you want to use this async messaging, go from async_messages import message_user Substitute your classical messages.add_message(... for message_user(request.user, "your message") where first agrument is a user object

  3. go to the django-async-messages package because it is slightly obsolete and needs a small update. Locate the middleware.py file in the package (likely in venv/Lib/site-packages/async_messages/middleware.py)

  4. Change it from this

    from django.contrib import messages

    from async_messages import get_messages

    class AsyncMiddleware(object):

     def process_response(self, request, response):
         """
         Check for messages for this user and, if it exists,
         call the messages API with it
         """
         if hasattr(request, "session") and hasattr(request, "user") and request.user.is_authenticated():
             msgs = get_messages(request.user)
             if msgs:
                 for msg, level in msgs:
                     messages.add_message(request, level, msg)
         return response
    

to this:

from django.contrib import messages

from async_messages import get_messages
from django.utils.deprecation import MiddlewareMixin

class AsyncMiddleware(MiddlewareMixin):

    def process_response(self, request, response):
        """
        Check for messages for this user and, if it exists,
        call the messages API with it
        """
        if hasattr(request, "session") and hasattr(request, "user") and request.user.is_authenticated:
            msgs = get_messages(request.user)
            if msgs:
                for msg, level in msgs:
                    messages.add_message(request, level, msg)
        return response

That is it - you have asynchronous messaging!

Ps - because you just edited a package which would change when deploying - I exctracted the package and with above changes I included it directly in my project structure.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1