1

The following problem is occurring in a large django project. I've been able to replicate the issue in a small mock-up project (code below).

I am trying to use the django messaging framework within an inclusion tag to display a message when a POST'ed form returns is_valid(). This approach has also been used in an another answer here (see 'final update' section).

The problem is that the message is not immediately displayed when the page is rendered after the POST. Instead the message appears the next time you navigate elsewhere or refresh the page after the POST response is received.

I am not receiving any errors. Everything appears to be operating normally, except for the delayed message display.

The reason for this approach is because I'm reusing multiple small forms across multiple apps and I need to use DRY principals for the GET and POST logic. This approach works perfectly - except for the issue with the delayed 'success' message display!

Really appreciate any feedback or assistance!

EDIT: To be clear the line which sets the message is in 'my_template.py':

messages.add_message(context['request'], messages.SUCCESS, "Successfully added entry")

The Demo Project:

settings.py:

...
    TEMPLATE_CONTEXT_PROCESSORS = (
       "django.core.context_processors.request",
       "django.core.context_processors.media",
       "django.contrib.messages.context_processors.messages"
    )
...

base_layout.html:

<!DOCTYPE html>
<html>
<head>
    <title>Test</title>
</head>
<body>
{% for message in messages %}<div class="alert{% if message.tags %} alert-{{ message.tags }}{% endif %}" role="alert">{{ message }}</div>{% endfor %}
{% block content %}{% endblock %}
</body>
</html>

my_template.html:

<form action="" method="post">
    {% csrf_token %}
    {{ form }}
    <input type="submit" value="Submit" />
</form>

forms.py:

from django.forms.models import ModelForm
from app.models import ContactMessage

class ContactForm(ModelForm):
    class Meta:
        model = ContactMessage
        fields = ['name']

index.html:

{% extends "app/base_layout.html" %}
{% load my_template %}
{% block content %}
{% my_template %}
{% endblock %}

my_template.py:

from django import template
from django.contrib import messages
from app.forms import ContactForm
register = template.Library()


@register.inclusion_tag('app/my_template.html', takes_context=True)
def my_template(context):

    if context['request'].method=='GET':
        return { 'form':ContactForm() }

    if context['request'].method=='POST':
        form = ContactForm(context['request'].POST)
        if not form.is_valid():
            return { 'form': form }

        form.save()

        messages.add_message(context['request'], messages.SUCCESS, "Successfully added entry")
        return { 'form':ContactForm() }
Community
  • 1
  • 1
Bosco
  • 935
  • 10
  • 18

2 Answers2

0

The messaging framework works through middleware, what you need is some way of informing the posting in the same request/response cycle. You have the context variable at hand, so why not add a value to it:

if form.is_valid():
    context['success']=True
else:
    context['success']=False

Then in your template:

{%if success %}<div>whoohoo!</div>{%endif%}
professorDante
  • 2,290
  • 16
  • 26
  • Thanks for the suggestion. However I'm already using the messaging framework heavily throughout the rest of my project and this solution would mean I'd either need to manage two different massaging approaches, or ditch the messaging framework and use a custom solution. Is there another approach I can use to isolate my reusable forms, instead of inclusion_tag, that I'm not aware of? I'm still relatively new to django. Thanks again – Bosco Jan 24 '15 at 21:33
  • Not sure I understand that - why ditch the messaging framework? I'm sure it works well for other parts of your project, but it wont work for what you want it for here. – professorDante Jan 24 '15 at 23:04
  • Just trying to be consistent with messaging. Since posting my original question I've realized there are other issues with POSTing within an inclusion tag, such as new data (as a result of the POST) is not rendered to the page - exact same issue as with the messaging system. Seems I need a different approach for writing re-usable views and forms. – Bosco Jan 25 '15 at 05:06
  • Hmm, yes. I use inclusion tags heavily to render re-usable forms, but still handle posting through the view, usually with AJAX. – professorDante Jan 25 '15 at 17:08
0

According to Django, the messages are queued for rendering until it is cleared by renderer. (reference)

In your case, you are adding messages after {{ message }} tags in base.html has been rendered. So your message is stored until your next view when {{ message }} in base.html is rendered again.

To solve this, you can move your {{ message }} tags behind {% endblock %} of content. Another possible solution is to use javascript to append {{ message }} tags either from my_template.html or from end of base.html.

wOxxOm
  • 65,848
  • 11
  • 132
  • 136
Moe
  • 1