Passing a dictionary to Django's messages framework
Sending in a dictionary as an argument to the message string in messages.add_message
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