【问题标题】:Django - How to show messages under ajax functionDjango - 如何在 ajax 函数下显示消息
【发布时间】:2012-10-26 17:56:15
【问题描述】:

我正在使用 AjaxForm 插件提交我的表单而不刷新。喜欢:

$('#my_form_id').ajaxForm(function(){

        //something on success or fail
    });

这可以正常工作。当我单击提交按钮时,它会保存表单数据而不刷新。但在此之前;我的模板文件上有 django 消息,例如:

{% for message in messages %}
    <div id="notice" align="center">
        {{ message }}
    </div>
{% endfor %}

此代码的作用是在帖子保存正确或失败时显示通知。

现在;我不能那样做。我不明白如何将这些消息标签与 ajax 函数一起使用。

它只是保存帖子。没有通知。

谢谢。

编辑:

add_post 网址:url(r'^admin/post/add/$', view='add_post',name='add_post'),

相关观点:

@login_required(login_url='/login/')
def add_post(request):
    template_name = 'add.html'
    owner = request.user
    if request.method == "POST":
        form = addForm(request.POST)
        if form.is_valid():
            titleform = form.cleaned_data['title']
            bodyform = form.cleaned_data['body']
            checkform = form.cleaned_data['isdraft']

            n = Post(title=titleform, body=bodyform, isdraft=checkform, owner=owner)
            n.save()
            messages.add_message(request, messages.SUCCESS,
                'New post created successfully!')
        else:
            messages.add_message(request, messages.WARNING,
                'Please fill in all fields!')
    else:
        form = addForm()
    return render_to_response(template_name, {'form': form, 'owner': owner,},
        context_instance=RequestContext(request))

【问题讨论】:

  • 您应该粘贴您的网址并查看。
  • 添加了 url 和视图部分。

标签: django jquery django-templates


【解决方案1】:

这些是帮助我解决问题的工具/方法。首先,我有一个名为render_to_json 的辅助实用方法:

# `data` is a python dictionary
def render_to_json(request, data):
    return HttpResponse(
        json.dumps(data, ensure_ascii=False),
        mimetype=request.is_ajax() and "application/json" or "text/html"
    )

我有一个messages.html 模板来呈现弹出消息所需的 html:

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

创建响应 AJAX 请求的消息时,我使用 Django 的 render_to_string 将消息打包成一个字符串,该字符串存储在 data 字典中,然后使用我的 render_to_json 返回一个适当的回应:

def my_custom_view(request)
    # ...  your view code
    data = {
        'msg': render_to_string('messages.html', {}, RequestContext(request)),
    }
    return render_to_json(request, data)

然后,在我的 jQuery $.post(...) 回调函数中,我检查 response 对象是否具有 msg 属性,然后将 response.msg 的内容插入到我想要的 DOM 中, 如果需要,可以使用 jQuery 转换。我的base.html 模板包含消息的&lt;ul&gt; 容器:

<ul id="popup-messages-content">
    {% include 'messages.html' %}
</ul>

请注意,当您想在实际页面加载(非 AJAX 请求)上显示消息时,上述内容包括 messages.html - 如果没有消息,则为空白,但 &lt;ul&gt; 仍然可用将 AJAX 接收到的消息推送到。

最后一部分是我在任何$.post(...) 回调中使用的 Javascript 函数(需要 jQuery)来显示消息:

function showPopupMessage(content) {
    var elMessages = $('#popup-messages-content');
    if (elMessages.length && content) {
        elMessages.html(content);
    }
}

【讨论】:

  • 如果这提供了您需要的答案,您可以这样标记吗?谢谢!
  • 嗯,这很尴尬...抱歉回复晚了。刚刚接受它:)
【解决方案2】:

您只需像往常一样创建消息,然后在发送响应之前将它们放入字典列表中:

django_messages = []

for message in messages.get_messages(request):
    django_messages.append({
        "level": message.level,
        "message": message.message,
        "extra_tags": message.tags,
})

然后你添加任何数据和你的消息并序列化它,例如:

data = {}
data['success'] = success
data['messages'] = django_messages

return HttpResponse(simplejson.dumps(data), content_type="application/json")

终于在你的 ajax 上:

success: function(data){
                                success = data.success;
                                update_messages(data.messages);
                                if (success){
                                    ...                                                                             
                                }
                            },

还有 update_messages 函数:

function update_messages(messages){
$("#div_messages").html("");
$.each(messages, function (i, m) {
                $("#div_messages").append("<div class='alert alert-"+m.level+"''>"+m.message+"</div>");
            });
    

}

效果很好,我发现它很容易实现

【讨论】:

  • 你的m.div_messages变量不应该分别是m.levelm.message吗?
  • 你也不想message.level_tag而不是message.level吗?
  • 您对变量的看法是对的,只是将代码翻译成英文时出现了错误。关于 level_tag 与 level 我不确定,我实际上并没有在我的代码中使用它。感谢您的更正。
  • @steven2308 老兄,你上面的第一个链接坏了! :P 请修复
  • @AbstractSpacecraft 我找不到它,那是 6 年前的事了,抱歉。反正。对于给定的问题,这个答案是完整的,不需要外部资源。
【解决方案3】:

这是一个简单的想法。

在 layout.html 中为您的消息添加一个占位符,这允许在 javascript 中附加新消息:

<div id="messages">
{% for message in messages %}
    <div id="notice" align="center">
        {{ message }}
    </div>
{% endfor %}
</div>

代替:

{% for message in messages %}
    <div id="notice" align="center">
        {{ message }}
    </div>
{% endfor %}

在add.html中,添加另一个如:

{% if messages %}
<ul class="hidden-messages" style="display:none">
    {% for message in messages %}
        <div id="notice" align="center">
            {{ message }}
        </div>
    {% endfor %}
</ul>
{% endif %}

而 ajaxForm 看起来像:

$('#your_form_id').ajaxForm({
    success: function(responseText) {
        var newMessages = $(responseText).find('.hidden-messages').html();
        $('#messages').append(newMessages);
    },
});

【讨论】:

  • 嗯。你能给我写一些解释代码吗?对我来说理解正确吗?
【解决方案4】:

在模板中

<div id="ajax_message">
    {% if messages %}
        {% for message in messages %}
            <div class="alert alert-{{ message.tags }}  fade show">
                {{ message|safe }}
            </div>
        {% endfor %}
    {% endif %}
</div>

ajax_send 后启动函数

$("#ajax_message").load("this_url #ajax_message");

function alert_message() {
    var pathname = window.location.pathname;
    $("#ajax_message").load(pathname+" #ajax_message");
}

【讨论】:

  • 我没有让这个工作,但我赞成召唤你:P
【解决方案5】:

使用 django-bootstrap5 lib 时如何做到这一点:

向只返回自定义 messages.html 模板的消息视图发出 AJAX 获取请求。

好的,我回顾了迄今为止在这个问题上所做的一些工作,我想出了一个巧妙的解决方案,可能与上面的重复,但是,我的帖子与我专门解决这个问题的帖子不同使用 django-bootstrap5 的编码人员的问题。因此,如果是您,请进一步阅读,这可能会解决您的问题。

这里的&lt;DefaultApp&gt; 是某些 IDE 为 Django 项目创建的默认应用程序。我当前的项目名为AbstractSpacecraft,它还有一个名为AbstractSpacecraft 的子文件夹,其中包含settings.py,我将其称为默认应用程序。

&lt;DjangoProject&gt;/&lt;DefaultApp&gt;/javascript_tools.js:

window.messages_tag_id = "#django-messages-div";
window.messages_url = null;

function load_html_from_url(url, elem) {
    $.get(url, function(data, status) {
        elem.html(data);
    });   
}

function display_django_messages() {
    messagesDiv = $(window.messages_tag_id);
    messagesDiv.empty();
    load_html_from_url(window.messages_url, messagesDiv);
}

function post_string_to_url(data, url)
{
    $.ajax({
        type: 'POST',
        url: url,
        data: data,
        success: function(data, status, xhr) {         // Function( Anything data, String textStatus, jqXHR jqXHR )
            if ('msg' in data) {
                const msg = data['msg'];
                console.log(msg);
                display_django_messages();
            }
        },
        error : function(xhr, errmsg, err) {
            // Provide a bit more info about the error to the console:
            if (errmsg) {
                console.log('ERROR: ' + errmsg);
                display_django_messages();
            }
            console.log(xhr.status + ": " + xhr.responseText);             
        }
    });
}

function csrf_safe_method(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

function setup_ajax_csrf_token(csrf_token) { 
    // BUGFIX.  This took hours to get to work!  
    // And remember the csrf_token line at the top of template
    window.csrf_token = csrf_token;
    
    $.ajaxSetup({
        beforeSend: function(xhr, settings) {
            if (!csrf_safe_method(settings.type) && !this.crossDomain) {
                xhr.setRequestHeader("X-CSRFToken", csrf_token);
            }
        }
    });
}

`

&lt;DjangoProject&gt;/templates/&lt;AppName&gt;/your_template.html(仅相关部分):

<script>
    $(document).ready(function()
    {
        // Remember to call this!
        setup_ajax_csrf_token("{{ csrf_token }}");   

        let ui = window.ui;
            
        $("#diagram-name-form").submit((event) => {
            event.preventDefault();
            const data = {
                "diagram name" : $("#diagram-name-input").val(),
                "diagram id" : "{{ diagram_id }}",
            };
            const set_name_url = "{% url 'set_model_string' Model='Diagram' field='name'%}";
            
            post_string_to_url(data, set_name_url, "{% url 'messages' %}");
        });
    });        
    
</script>

 .....

<div class="form-outline">
    <form class="row row-cols-lg-auto g-3 align-items-center" method="post"
        id="diagram-name-form">
        {% csrf_token %}
    
        <input type="text" id="diagram-name-input" class="form-control" placeholder="Diagram name?" />
    </form>
</div>

&lt;DjangoProject&gt;/templates/&lt;DefaultApp&gt;/messages.html:

{% load django_bootstrap5 %}

{% autoescape off %}{% bootstrap_messages %}{% endautoescape %} 

&lt;DjangoProject/&lt;DefaultApp&gt;/views.py:

from django.shortcuts import render
from django.views.generic.base import TemplateView, View

class MessagesView(View):
    template_name = 'AbstractSpacecraft/messages.html'

    def get(self, request, *args, **kwargs):
        return render(request, self.template_name)

&lt;DjangoProject&gt;/&lt;DefaultApp&gt;/base.html:

{% block bootstrap5_content %}
  {% block as_navbar %}  <!-- as = AbstractSpacecraft -->
   ....
  {% endblock %}
  
  <div class="container-fluid">
      <div class="row">
          <div class="col">
              <div class="row" id="django-messages-div">
                {% autoescape off %}{% bootstrap_messages %}{% endautoescape %}              
              </div>              
              {% block content %}{% endblock %}                
          </div>
      </div>
  </div>
{% endblock %}
....

基本上,在我们收到来自 ajax POST 请求的 OK 后,我们会执行 ajax GET 请求,现在一切正常,它可能会工作,但我无法通过查看“网络”选项卡让 messagesDiv.load(url) 工作在 Chrome DevTools 和流量分析器下,当一切正常时,您应该会看到一个 POST 请求,然后是一个 GET 请求。

ajax GET 简单地获取一个messages.html 模板,然后我们用新近知道的消息填充该模板。我们确保首先清除messageDiv,这样消息就不会堆积在 gui 上。

【讨论】:

  • 好的,elem.load(url) 现在似乎可以工作了(而且可能一直都在工作)。所以请使用 it 而不是 AJAX 获取。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-09
  • 1970-01-01
  • 2012-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-20
相关资源
最近更新 更多