1

我有一个 Django 应用程序,有两种类型的用户,我们称它们为 A 和 B。这两种用户类型有不同的导航栏。用户类型 A 在其导航栏中有一个链接,允许他们发送消息。发送消息表单出现在叠加层中,因此表单需要出现在每个模板中,或者通过 AJAX 获取。这些用户可以从网站上的任何/每个页面发送消息,并且每个页面都有自己的视图。如果消息有错误,用户应该返回到他们所在的同一页面,并且错误应该显示在表单叠加层中。如果发送成功,他们应该被重定向到显示他们消息的新页面。

目前,我已将表单放入一个单独的模板中,该模板包含在用户类型 A 的所有页面中。我将表单操作指定为名为 send_message 的视图,并告诉该视图呈现到此模板。视图永远不会被调用,所以我想这不是正确的方法。

如何在每个模板中呈现此表单?我需要从每个视图调用一个函数,还是使用一个特殊的模板标签(我查看了包含标签,但我认为它们不适合这种情况)?或者我应该使用 AJAX 获取表单吗?我是否将表单视图添加到每个 URL?

编辑:添加一些代码来解释。

比如说,我在一个页面上有一个简单的视图,如下所示:

@login_required
def index_view(request, place_id):
    categories = Category.objects.all()
    return render(request, 'places/categories.html', {'place_id': place_id, 'categories': categories})

此页面的模板是从其中包含导航栏的模板扩展而来的,该模板包括发送消息表单,如下所示:

<div id="message-popup">
    <h1>NewMessage</h1>
        <form action="{% url "send_message" %}" method="post">
            {% csrf_token %}
            {% get_message_form as message_form %}
            <table>
                <tr>
                    <td>{{ message_form.recipient.label_tag }}{{ message_form.recipient }}</span></td>
                    <td>{{ message_form.title.label_tag }}{{ message_form.title }}</td>
                </tr>
            <tr>
                <td>{{ message_form.categories.label_tag }}{{ message_form.categories }}</td>
                <td>
                    {{ message_form.content.label_tag }}{{ message_form.content }}
                    <button type="submit" class="button">Send</button>
                    <button class="box-close button">Cancel</button>
                </td>
            </tr>
        </table>
    </form>
</div>

该表单发布到此视图:

def send_message_view(request, place_id):
    place = Place.objects.get(id=place_id)
    if request.POST:   
        user = get_user_class(request.user)
        message_form = forms.SendMessageForm(request.POST, place=place, user=user)
        if message_form.is_valid():
            message_form.save()
            # redirect to page showing the message
    else:
        message_form = forms.SendMessageForm(place=place, user=user)
    return render(request, 'messaging/send_message_form.html', {'message_form': message_form})

我缺少的步骤是如何让表单首先呈现。当我转到类别页面时,表单不存在 - 显然是因为上下文中没有 message_form 变量。那么我可以让我的 send_message_view 和我的 index_view 运行和呈现这两个模板,还是有其他方法我必须将它们链接在一起?

编辑:

好的,这是我的模板标签:

@register.inclusion_tag('messaging/send_message_form.html', name='get_message_form', takes_context=True)
def get_message_form(context, place, sender, recipient):
    message_form = SendMessageForm(context['request'].POST or None, place=place, sender=sender, recipient=recipient)
    url = None
    if context['request'].method=='POST' and message_form.is_valid():
        message = message_form.save()
        url = reverse('conversation', kwargs={'place_slug': place.slug, 'message_id': message.id})
        """ This doesn't work
        return HttpResponseRedirect(url) """
    return {'message_form': message_form, 'place_id': place.id, 'message_sent_url': url}

我不能从模板标签做一个 HttpResponseRedirect,所以我需要找到一些其他的方法来重定向到成功页面。我可以将重定向 URL 发送到模板,但我不知道从那里可以用它做什么......

4

1 回答 1

2
  1. 您有两个选择 - 将表单放在 base.html 模板文件中,并让每个模板都继承自该文件,或者制作一个单独的模板文件,就像您现在所做的那样,然后将其 {%include%} 放在您想要的任何位置.
  2. 不确定“从每个视图调用一个函数”是什么意思。视图是一个函数或一个类。
  3. AJAX 功能是一个单独的问题——首先根据需要获取表单呈现,所有继承都使用同步调用。如果需要,然后实现 AJAX。
  4. 您的表单将转到您在该表单中指定的 url,因此只有该视图函数需要表单逻辑。更新:

看起来您想要一个自定义包含标签来呈现您的表单。

@register.inclusion_tag('<your-form-render-template.html>')
    def get_message_form(place_id, user):
        return {'message_form': SendMessageForm(Place(id=place_id), user)}

然后在您的 index.html 模板中:

{%load my-template-tags%}

<div id="message-popup">
    <h1>NewMessage</h1>
    {%get_message_form place_id request.user%}
</div>

您使用标签注册的模板文件然后呈现表单:

    <form action="{% url "send_message" %}" method="post">
        {% csrf_token %}
        <table>
            <tr>
                <td>{{ message_form.recipient.label_tag }}{{ message_form.recipient }}</span></td>
                <td>{{ message_form.title.label_tag }}{{ message_form.title }}</td>
            </tr>
        <tr>
            <td>{{ message_form.categories.label_tag }}{{ message_form.categories }}</td>
            <td>
                {{ message_form.content.label_tag }}{{ message_form.content }}
                <button type="submit" class="button">Send</button>
                <button class="box-close button">Cancel</button>
            </td>
        </tr>
    </table>
</form>

现在,您想放置表单的任何地方,只需加载您的标签并将正确的参数传递给模板标签。繁荣!

添加标签有特定要求,例如应用程序结构等。在此处阅读。

更新:

好的,这很酷。您可以将上下文变量添加到包含标签中。现在您的标签如下所示:

@register.inclusion_tag('<your-form-render-template.html>', takes_context=True)
    def get_message_form(context):
        message_form = forms.SendMessageForm(context['request'].POST or None, place=context['place_id'], user=context['request.user'])
        if context['request'].method=='POST' and message_form.is_valid():
            #redirect to thanks

        return {'message_form': SendMessageForm(Place(id=place_id), user)}

现在,您的包含标签的用途与旧表单视图功能相同。您的表单现在可以只包含一个操作“.”,它不需要在表单上执行任何逻辑,标签会执行此操作。

请注意,您的模板中有错误 - 您需要使用 {{message_form.errors}} 显式显示表单错误。

感谢这个很好的问题 - 以前从未这样做过,而且它非常强大。

最后更新!!!

好的,对您的最后一点帮助,那么您就靠自己了 :-) 它可能不适用于重定向,因为此包含标记仅返回要显示的更新的上下文变量。换句话说,一旦你到达这里,你就无法重定向。因此,由于我们只想向用户显示一条消息说“你成功了”,所以让我们使用消息传递框架。

@register.inclusion_tag('messaging/send_message_form.html', name='get_message_form', takes_context=True)
def get_message_form(context, place, sender, recipient):
    from django.contrib import messages

    message_form = SendMessageForm(context['request'].POST or None, place=place, sender=sender, recipient=recipient)
    url = None
    if context['request'].method=='POST' and message_form.is_valid():
        message = message_form.save()
        messages.add_message(context['request'], messages.INFO, "Dante Rules!")

    return {'message_form': message_form, 'place_id': place.id, 'message_sent_url': url}

现在该消息将在您的主模板中可用,因此您可以在使用包含标记呈现表单后检查它:

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

一旦它被渲染,它就会从上下文中消失,这对我们的例子来说是完美的。因此,您可以在 JQuery UIDialog、页面的另一部分或其他任何地方显示它。无论如何,它看起来比重定向恕我直言更好,因为您停留在发送消息的同一页面上。

于 2013-09-21T18:22:56.030 回答