Anjanesh Lekshminarayanan
Anjanesh

Anjanesh

Passing a dictionary to Django's messages framework

Sending in a dictionary as an argument to the message string in messages.add_message

Anjanesh Lekshminarayanan's photo
Anjanesh Lekshminarayanan
·Aug 23, 2022·

3 min read

Subscribe to my newsletter and never miss my upcoming articles

In order to display some 'flash' message after a form submission like a success message or an error message we make use of messages framework which is built-in in Django.

I was doing a return redirect('dashboard') from a job posting form. Thing is, I am redirecting to the dashboard from many such forms which are located in different pages. I wasn't redirecting to a dedicated page unique to each form submission like job post, contact etc - as a result, I don't know details such as, from which page its come from, or other success form submission data, specific to the page, that are required to be shown on the dashboard.

In views.py :

from django.contrib import messages

In class AddJob(LoginRequiredMixin, generic.CreateView): of views.py :

def form_valid(self, form):
    form.instance.user = self.request.user
    super(AddJob, self).form_valid(form)

    data = {
        "section": "job",
        "message": "You've successfully posted a job - thank you - it'll be available post approval",
        "some_other_data_1": "foo",
        "some_other_data_2": "bar"
    }

    messages.add_message(self.request, messages.SUCCESS, data, extra_tags="dictionary")

    return redirect('dashboard')

An example of sending in a message is as follows :

messages.add_message(request, messages.INFO, 'Hello world.')

The actual message, 'Hello world.' is a string.

There's one slight problem using this method of sending in data which is a dictionary - it'll be converted to a string and the resultant message argument would be

'{"section": "job", "message": "You\'ve successfully posted a job - thank you - it\'ll be available post approval", "some_other_data_1": "foo", "some_other_data_2": "bar" }'

which is not a dictionary but rather a string containing the dict.

I searched for a lot of workarounds to pass in an actual dict to add_message but in vain.

{{ message }} below will output the string representation of the python dictionary data.

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

So we won't be able to do things like {{ message.section }} or {{ message.message }} or {{ message.some_other_data_1 }}

Enter JavaScript :

Load AlpineJS in your base HTML template : (this is only to make life simpler instead of doing something like divElement.innerHTML = data.message etc or using jQuery)

<script src="https://unpkg.com/alpinejs@3.10.3/dist/cdn.min.js" defer></script>

Now in <app>/templates/dashboard.html, message.tags will be 'dictionary success' since we passed in extra_tags="dictionary" to messages.add_message before.

<div>
    {% if messages %}
        {% for message in messages %}
            {% if 'dictionary' in message.tags %}
                <script>
                    let data = {{ message | safe }};
                    console.log(data);
                </script>
                <div x-data="{ message_data : data }">
                    <h3>Message :</h3>
                    <p x-text="message_data.section"></p>
                    <p x-text="message_data.message"></p>
                    <p x-text="message_data.some_other_data_1"></p>
                </div>
            {% else %}
                <div>{{ message }}</div>
            {% endif %}
        {% endfor %}
    {% endif %}
</div>

x-text="message_data.section" will have the element's (in this case the p tag) content to have the value of message_data.section which is job

 
Share this