如何在多个模板中包含表单 [英] How to include a form in multiple templates

查看:116
本文介绍了如何在多个模板中包含表单的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个具有两种类型的用户的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 ={%urlsend_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 =submitclass =button>发送< / button>
< button class =box-close button>取消< / button>
< / td>
< / tr>
< / table>
< / form>
< / div>

表单发布到此视图:

  def send_message_view(request,place_id):
place = Place.objects.get(id = place_id)
如果request.POST:
user = get_user_class (request.user)
message_form = forms.SendMessageForm(request.POST,place = place,user = user)
如果message_form.is_valid():
message_form.save()
#重定向到显示消息的页面
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来运行和渲染两个模板,还有其他一些方法我必须链接在一起?



编辑: / p>

确定,这里是我的模板标签:

  @register。 include_tag('messaging / send_message_form.html',name ='get_message_form',took_context = True)
def get_message_form(context,place,sender,recipient):
message_form = SendMessageForm(context ['request'] .POST或None,place = place,sender = sender,recipient = recipient)
url = None
如果上下文['request']。method =='POST'和message_form.is_valid():
message = message_form.save()
url = reverse('conversation',kwargs = {'place_slug':place.slug,'message_id':message.id})
不工作
return HttpResponseRedirect(url)
return {'message_form':message_form,'place_id':place.id,'message_sent_ur l':url}

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

解决方案

你有两个选择 - 将表单放在你的base.html模板文件中,并使每一个模板从中继承,或者制作一个单独的模板文件,就像你目前所做的那样, {%include%}它无论你想要什么。

  • 不知道你的意思是从每个视图调用一个函数。视图是一个函数或类。

  • AJAX功能是一个单独的问题 - 首先要获得窗体渲染,您的所有继承使用同步调用。然后实现AJAX,如果你想要的话。

  • 你的表单将转到您在该表单中指定的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 ={%urlsend_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 =submitclass =button>发送< / button>
    < button class =box-close button>取消< / button>
    < / td>
    < / tr>
    < / table>
    < / form>

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



    有添加标签的特定要求,如应用程序结构等。请阅读 here



    更新:



    好的,这很酷您可以将上下文变量添加到您的包含标记中。现在你的标签看起来像这样:

      @ register.inclusion_tag('< your-form-render-template.html> ,takes_context = True)
    def get_message_form(context):
    message_form = forms.SendMessageForm(context ['request']。POST或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}}显式显示表单错误。



    感谢这个优秀的问题 - 从来没有这样做过,它的超强大。



    FINAL UPDATE !!!



    确定,最后一点帮助你,然后你在你的自己:-)这可能不是在重定向工作,因为这个包含标签只是返回更新的上下文变量来显示。换句话说,一旦你到这里,你不能重定向。所以,由于我们只想向用户显示一条消息,指出你是成功的,请使用消息传递框架。

      @ 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 [请求']。POST或None,place = place,sender = sender,recipient = recipient)
    url =无
    如果context ['request']。method =='POST'和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}

    将在您的主模板中可用,所以您可以在使用包含标签呈现表单之后检查它:

      {%在邮件中的消息%} 
    < li {%if message.tags%} class ={{message.tags}}{%endif%}> {{message}}< / li>
    {%endfor%}

    一旦呈现,它将从上下文中消失,完美的我们的情况。所以你去,你可以显示它在一个JQuery UIDialog,页面的另一部分,或什么。它看起来比直接的IMHO更好,因为你留在你发送消息的同一页上。


    I have a Django app with two types of users, lets call them A and B. The two user types have different navigation bars. User type A has a link in their navigation bar to allow them to send a message. The send message form comes up in an overlay, so the form needs to be present in every template, or fetched over AJAX. These users can send a message from any/every page on the site, and each page has its own view. If a message has errors, users should be returned to the same page they were on, and errors should be shown in the form overlay. If it is sent successfully, they should be redirected to a new page that shows their message.

    Currently, I have put the form into a separate template that is included on all pages for user type A. I specified the form action as a view called send_message, and I have told that view to render to this template. The view is never called, so I guess this isn't the right way to do it.

    How can I render this form in every template? Do I need to call a function from each view, or use a special template tag (I looked at inclusion tags, but I don't think they're right for this situation)? Or should I fetch the form using AJAX? Do I add the form view to every URL?

    EDIT: Adding some code to explain.

    Say, for example, I am on a page with a simple view like this:

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

    The template for this page is extended from a template with the nav bar in it, and that template includes the send a message form, which looks like this:

    <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>
    

    That form posts to this view:

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

    The step I'm missing is how to get the form to render in the first place. When I go to the categories page, the form isn't there - obviously because there is no message_form variable in the context. So can I get my send_message_view and my index_view to both run and render the two templates, or is there some other way I have to link it all together?

    EDIT:

    OK, here is my template tag now:

    @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}
    

    I can't do an HttpResponseRedirect from the template tag, so I need to find some other way of redirecting to the success page. I can send the redirect URL on to the template, but I don't know what I can do with it from there...

    解决方案

    1. You have two choices - place the form in your base.html template file, and make every template inherit from that, or make a separate template file, as you have done at the moment, and {%include%} it wherever you want it.
    2. Not sure what you mean by 'call a function from each view'. A view is a function or a class.
    3. The AJAX functionality is a separate issue - get the form rendering as you want it first, with all your inheritance working with a synchronous call. Then implement the AJAX if you want it.
    4. Your form will go to the url you specify in that form, so only that view function will need the form logic. UPDATE:

    Looks like you want a custom inclusion tag to render your Form.

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

    And then in your index.html template:

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

    Your template file you registered with your tag then renders the form:

        <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>
    

    Now anywhere you want to put your form, just load your tag and pass in the correct args to the template tag. Boom!

    There are specific requirements for adding tags, such as app structure etc. Read up on it here.

    UPDATE:

    OK, this is cool. You can add in the context variable into your inclusion tag. Now your tag looks like this:

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

    Now your inclusion tag serves the same purpose as your old form view function. Your form can now just have an action ".", which wont need to perform any logic on the form, the tag does it.

    Note you have an error in your template - you need to explicitly show the form errors with {{message_form.errors}}.

    Thanks for this excellent question - never done this before, and it's super powerful.

    FINAL UPDATE!!!

    OK, last bit of help for you, then you're on your own :-) It's probably not working on the redirect as this inclusion tag just returns the updated context variable to display. In other words, you cant redirect once you get here. So, as we only want to display a message to the user saying 'you were successful', lets use the messaging framework.

    @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}
    

    Now that message will be available in your main template, so you can check for it after you render the form with the inclusion tag:

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

    Once it's been rendered, it disappears from context, which is perfect for our case. So there you go, you can display it in a JQuery UIDialog, another part of the page, or whatever. It looks better than a re-direct IMHO anyways, as you stay on the same page you sent the message from.

    这篇关于如何在多个模板中包含表单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆