Django - 具有自动完成功能的 Javascript 动态内联 FormSet

标签 django autocomplete django-forms

我正在尝试制作一种能够附加参与者的调度程序事件编辑器。

模型

class Session(models.Model):
  start_time = models.DateTimeField()
  end_time = models.DateTimeField()

class Participation(models.Model):
  session = models.ForeignKey(Session)
  participant = models.ForeignKey(User)
  status = models.CharField(max_length=1, choices=STATUSES)

在编辑器中,我希望有一个自动完成搜索输入,我可以从中找到要添加到 session 中的用户

预览

Session Editor

在这里,我输入了“laurent”,我将通过单击结果名称之一来添加一个人
参与者的颜色取决于他们的状态

我有一个定义了开始和结束时间的 Session 对象的表单
现在我想我应该有一个用于参与内联表单集

问题

  • 您是否建议我为参与者使用内联表单集
  • 如何动态添加/删除参与者行?

最佳答案

这个问题看起来很简单,但正确的回答需要几个答案。

我将使用 jQuery 逐点给出我的解决方案。

自动完成

这是简单的部分。您可以使用类似 select2 的插件或jqueryui autocomplete以及找到类似用户的 View

def search_users(request):
    search = request.GET.get('term')
    users = User.objects.filter(
      Q(first_name__icontains=search)
    | Q(last_name__icontains=search)
    )
    ulist = list({'id': u.id, 'value': u'%s %s' % (u.first_name, u.last_name)}
        for u in users)
    return JsonResponse(ulist)

此 View 与默认的 jQuery UI 自动完成插件兼容

动态表单集

这是一个棘手的问题。关键是要利用 management_formform.DELETE。这是我的解决方案:

  • 为参与者使用内联表单集(带有一个额外的表单)
  • 打印management_form
  • 在自动完成选择后,通过克隆隐藏的空表单(额外的表单)并递增 id_form-TOTAL_FORMS 来使用 jQuery 添加表单行
  • 通过隐藏表单行并选中隐藏的删除复选框,使用 jQuery 删除表单行

模板

<form method="post">{% csrf_token %}
{{ sessionform }}
<div>
{{ participant_formset.management_form }}
  <label for="part_search">Search: </label><input id="part_search" />
    <ul id="participation_set">
{% for tform in participant_formset %}
    {{ tform.id }}
      <li>
        <span class="participant">
          {{ tform.participant }}{{ tform.instance.participant.name }}
        </span>
        <span class="status">{{ tform.status }}</span>
        <span class="delete ui-icon ui-icon-circle-minus">
          {{ tform.DELETE }}
        </span>
      </li>
{% endfor %}
    </ul>
</div>
</form>

CSS

/* Delete button */
#participation_set .delete {
  display: inline-block;
  vertical-align: middle;
  cursor: pointer;
}

/* Hidden delete checkbox */
#participation_set .delete input {
  display: none;
}

/* Deleted form */
#participation_set li.deleted {
  display: none;
}

/* Last hidden form to clone */
#participation_set li:last-child {
  display: none;
}

jQuery
/*! This adds a form line
 * Call it on autocomplete select
 */
function add_aform(inst, item) {
  if ($(':input[name$="participant"][value=' + item.id + ']').length) {
    return false;
  }
  var total = $('#id_' + inst + '-TOTAL_FORMS').val();
  var sul = '#' + inst;
  var li = $(sul + ' li:last-child');
  var new_li = li.clone().appendTo(sul);
  li.find('span.participant').append(item.label);
  li.find(':input[name$="participant"]').val(item.id);
  new_li.find(':input').each(function () {
    var new_name = $(this).attr('name')
      .replace('-' + (total - 1) + '-', '-' + total + '-');
    $(this).attr('name', new_name);
  });
  new_li.find('label').each(function () {
    var tmp = $(this).attr('for')
      .replace('-' + (total - 1) + '-', '-' + total + '-');
    $(this).attr('for', new_for);
  });
  new_li.find('.delete').click(del_aform);
  $('#id_' + inst + '-TOTAL_FORMS').val(++total);
}

/*! This removes a form line
 * Call it on click from delete buttons (placed inside each li)
 */
function del_aform() {
  $(this).parents('li').addClass('deleted');
  $(this).find(':checkbox').attr('checked', true);
}

我知道我也可以使用 empty_form 实例并使用 __prefix__ 来替换 ids,从而简化 JavaScript 以实现更好的可维护性,但我没有找到方法在真实形式和空形式之间分解代码。

查看

该 View 非常标准,使用 inlineformset_factory 并将 extra 设置为 1(以获取唯一要克隆的隐藏表单)。另外,不要忘记为字段 participant

使用 HiddenInput 小部件

关于Django - 具有自动完成功能的 Javascript 动态内联 FormSet,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10315479/

相关文章:

Python/Django 测试运行程序导入错误

css - Django:使用正确的 URL 从 S3 提供 CSS,但无法加载

javascript - 自定义自动完成 Angular Material

javascript - 根据在 Angular JS 中单击的列表项,为 ng-model ="searchText"输入赋值

python - Django AttributeError 'ModelFormOptions' 对象没有属性 'concrete_fields'

python - Django Forms 在 ManyToMany 字段中保存 request.user

python - Django 与内置 "User"模型的多对多关系

python - 将参数传递给 RegistrationView 的 form_class

google-chrome - 如何让 Chrome 使用正确的自动完成信息?

python - 如何在 Google App Engine 上的 django 中避免 NotImplementedError "Only tempfile.TemporaryFile is available for use"?