在一个页面中使用带有多个 django 表单的 jQuery datepicker

Posted

技术标签:

【中文标题】在一个页面中使用带有多个 django 表单的 jQuery datepicker【英文标题】:Using jQuery datepicker with multiple django forms in one page 【发布时间】:2016-11-30 10:51:40 【问题描述】:

所以我有一个创建公告表单,然后为每个公告创建一个编辑表单,每个表单都有自己的日期选择器。我控制日期选择器的功能是:

$(function() 
    $( ".datepicker" ).datepicker(
        changeMonth: true,
        changeYear: true,
    );
);

最初我的问题是在其中一个编辑表单中使用日期选择器会更改创建表单中的字段,因为 ID 相同。我通过添加 id(在我的 forms.py 中)来解决这个问题:

end_date = forms.DateField(label='Expires', widget=forms.TextInput(attrs='class':'datepicker form-control', 'id':'end_date_create'))

end_date = forms.DateField(label='Expires', widget=forms.TextInput(attrs='class':'datepicker form-control', 'id':'end_date_edit'))

到我的 createAnnouncement 和 EditAnnouncement 表单。但由于我每页有多个编辑表单,我仍然遇到同样的问题,即在任何编辑表单上使用日期选择器只会更改顶部编辑表单的字段。我正在使用 django 小部件调整来呈现我的表单,因此它会自动生成 html 和 ids 和类以及所有内容。每个编辑表单都在一个具有唯一 id 的 div 中,但表单字段本身在所有表单中都被命名为相同的东西。有谁知道如何使用 django 小部件调整为我的表单字段生成唯一 ID?或者也许有一些 javascript 或者我可以添加到我的 datepicker 函数中,告诉 datepicker 更改同一 div 中字段的值?

编辑:我的模板如下所示:

% if boardAnnouncements %
<h3>Announcements</h3>
    <div class="container" style="margin: 0px; padding: 0px;">
        <ul>
            % for announcement in boardAnnouncements %
                <div class="row" style="padding-bottom: 10px;">
                <li>
                    <div class="col-md-6">
                        <!-- display announcement content -->
                    </div>
                    <div class="col-md-6">
                        <!-- edit button calls javascript function to hide/unhide div with edit form in it -->
                        <a href="javascript:unhide_announcement('editann-announcement.id', 'announcement.id')" class="btn btn-primary" style="margin-left: 10px;"><i class="fa fa-pencil" aria-hidden="true"></i> Edit</a>
                    </div>
                </div>
                <!-- each div gets unique id that corresponds to announcemt id -->
                <div id="editann-announcement.id" class="hidden">
                    <form role="form" action="/editannouncement/announcement.id/" method="post">
                            <!-- display edit form with django widget tweaks -->
                            % csrf_token %
                            % for field in editAnnouncement %
                                % if field.errors %
                                    <div class="form-group has-error">
                                        <label class="col-sm-2 control-label" for="id_ field.name ">
                                         field.label </label>
                                        <div class="col-sm-10">
                                             field 
                                            <span class="help-block">
                                            % for error in  field.errors %
                                                 error 
                                            % endfor %
                                            </span>
                                        </div>
                                    </div>
                                % else %
                                    <div class="form-group">
                                        <label class="col-sm-2 control-label" for="id_ field.name "> field.label </label>
                                        <div class="col-sm-10">
                                             field 
                                            % if field.help_text %
                                                <p class="help-block"><small> field.help_text </small></p>
                                            % endif %
                                        </div>
                                    </div>
                                % endif %
                            % endfor %
                                <div class="form-group">
                                    <div class="col-sm-offset-2 col-sm-10">
                                        <button type="submit" name="edit_announcement" class="btn btn-primary">Save</button><br><br>
                                    </div>
                                </div>
                            </form>
                </li>
                </div>
            % endfor % 
        </ul>
    </div>  
    % endif %
<div>

并且为编辑表单生成的 HTML 是:

<div id="editann-1" class="unhidden">
    <form class="ng-pristine ng-valid" role="form" action="/editannouncement/1/" method="post">
        <input name="csrfmiddlewaretoken" value="AbTEZYmK1RF9yeom1C34IFFCj3EBrOD3" type="hidden">
        <div class="form-group">
            <label class="col-sm-2 control-label" for="id_description">Edit Description</label>
            <div class="col-sm-10">
                <textarea class="form-control" cols="40" id="id_description" name="description" rows="10"></textarea>
            </div>
        </div>
        <div class="form-group">
            <label class="col-sm-2 control-label" for="id_end_date">Expires</label>
            <div class="col-sm-10">
                <input class="datepicker form-control hasDatepicker" id="end_date_edit" name="end_date" type="text">
            </div>
        </div>
        <div class="form-group">
            <div class="col-sm-offset-2 col-sm-10">
                <button type="submit" name="edit_announcement" class="btn btn-primary">Save</button><br><br>
            </div>
        </div>
    </form>
</div>
<div id="editann-2" class="unhidden">
    <form class="ng-pristine ng-valid" role="form" action="/editannouncement/2/" method="post">
        <input name="csrfmiddlewaretoken" value="AbTEZYmK1RF9yeom1C34IFFCj3EBrOD3" type="hidden">
        <div class="form-group">
            <label class="col-sm-2 control-label" for="id_description">Edit Description</label>
            <div class="col-sm-10">
                <textarea class="form-control" cols="40" id="id_description" name="description" rows="10"></textarea>
            </div>
        </div>
        <div class="form-group">
            <label class="col-sm-2 control-label" for="id_end_date">Expires</label>
            <div class="col-sm-10">
                <input class="datepicker form-control hasDatepicker" id="end_date_edit" name="end_date" type="text">
            </div>
        </div>
        <div class="form-group">
            <div class="col-sm-offset-2 col-sm-10">
                <button type="submit" name="edit_announcement" class="btn btn-primary">Save</button><br><br>
            </div>
        </div>
    </form>
</div>

所以为了澄清每个editann-# div 里面都有一个编辑表单(每个编辑表单都有一个日期选择器)。现在,由于所有编辑表单“过期”字段的 id 为 id_end_date,因此无论我使用哪个日期选择器,日期选择器都会更改第一个编辑表单的值。

【问题讨论】:

究竟是什么问题?显示您呈现的 html 以及您希望将 datepicker js 应用于的表单部分以及您不希望将其应用于的表单部分。 @YPCrumble 我已经添加了模板代码并生成了 HTML,这有助于澄清问题吗? 想要的结果是什么?您希望第二个“过期”字段成为日期选择器而不是第一个?或者是其他东西?抱歉,仍然无法理解实际问题是什么。 不,所以当我单击文本输入区域时,每个表单都会显示 datepicker(这是我想要的),但是当我选择一个日期时,我的 datepicker 函数会填写第一个编辑表单的值.假设我的页面上有 3 条公告,我想编辑第三条的到期日期。我单击编辑按钮,编辑公告 div 被取消隐藏,我将光标放在过期字段中,日期选择器出现,我选择了一个日期,但该日期出现在第一个公告的编辑表单中,而不是第三个。所以我需要一种方法将每个日期选择器与正确的表单@YPCrumble 相关联 【参考方案1】:

我想出了一个涉及一些 javascript 和 jQuery 的解决方案。

function unhide_announcement(divID, ID) 
var item = document.getElementById(divID);
if (item) 
    /* hide/unhide div */
    item.className=(item.className=='hidden')?'unhidden':'hidden';
    /* give each end_date field a unique ID */
    var newID = 'id_end_date' + ID;
    item.querySelector('#id_end_date').id = newID;
    /* datepicker functionality */
    $(function()                                                     
        $( '#'+newID ).datepicker(
          changeMonth: true,
          changeYear: true,
        );
      )
    

由于每个编辑公告表单都在一个唯一的 div 中,我首先获取该 div,然后在 div 中只有 1 个编辑公告表单,因此我将该 id 从 id_end_date 更改为 id_end_date1 或任何公告 id有关联。然后我更改了 jQuery datepicker 函数,我必须按 id 而不是按类选择它,它起作用了。所以当我在我的模板中调用它时,它看起来像这样:

<a href="javascript:unhide_announcement('editann-announcement.id', 'announcement.id')" class="btn btn-primary">Edit</a>
<div id="editann-announcement.id" class="hidden">
    <!-- edit announcement form -->
    <form>
        ...
    </form>
</div>

【讨论】:

【参考方案2】:

你不应该在一个页面上有两个相同的id。 ID's must be unique。这就是造成错误的原因。

要在页面上添加多个表单,您应该使用Formsets,它会自动确保您的 id 是唯一的。

通过从您的代码中删除id 属性,我能够使日期选择器工作。见this working fiddle。

请注意,我必须从您粘贴的 html 中删除 hasDatepicker 类,因为它实际上是由 datepicker 函数插入的 - 如果您将其留在其中,则会产生冲突,并且日期选择器不会显示。

【讨论】:

我知道 id 需要是唯一的,但是 django 小部件调整会自动生成 HTML(包括 id)。这就是为什么我问是否有人知道如何通过小部件调整生成独特的。我在 for 循环中显示公告,因此它对每个公告执行完全相同的操作 @Catherine 因为这里有两个循环,您可以使用forloop.counterparentloop.counter 来使ID 独一无二。 这听起来很有帮助,但我在模板中实现它时遇到了麻烦,我尝试用 field|attr:"id:end_date_edit-forloop.parentloop.counter" 替换 field ,但它给了我一个错误 TemplateSyntaxError: attr requires 2 arguments, 1 provided。您的建议只是更改了 id 的标签,而不是表单字段的实际 id @Catherine 抱歉 - 你应该使用 Formset - 这将确保 id 对你来说是唯一的。 我最终编写了一些将 divID 和公告 ID 作为参数并将过期表单字段 ID 从“id_end_date”更改为“id_end_date”+ ID 但现在当我尝试使用日期选择器时得到错误“缺少此日期选择器的实例数据”所以你知道我可以如何更改我的日期选择器函数来处理 ids 而不是类?我对jQuery没有任何经验,我复制了这个函数,所以我不知道如何更改它

以上是关于在一个页面中使用带有多个 django 表单的 jQuery datepicker的主要内容,如果未能解决你的问题,请参考以下文章

在 Django 的一个页面上使用多个表单

带有modelchoicefield的Django多个表单->查询太多

POST表单提交后django显示消息

django:csrf_token 用于单个页面上的多个表单和 ajax 请求

Django - 从模板内部调用带有表单的视图

Django - 在多个页面上重用用户注册表单的系统架构