Delayed display of message from within an inclusio

2019-09-06 20:18发布

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() }

2条回答
小情绪 Triste *
2楼-- · 2019-09-06 21:03

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%}
查看更多
神经病院院长
3楼-- · 2019-09-06 21:14

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.

查看更多
登录 后发表回答