【问题标题】:Django - Javascript dynamic inline FormSet with autocompleteDjango - 带有自动完成功能的 Javascript 动态内联 FormSet
【发布时间】:2012-05-06 03:02:31
【问题描述】:

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

型号

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)

在编辑器中,我希望有一个自动完成搜索输入,我可以从中找到users 以添加到会话中

预览

在这里我输入了“laurent”,我将通过点击其中一个名字来添加一个人
参与者颜色取决于他们的status

我有一个Session 对象的表单,定义了开始和结束时间
现在我想我应该为Participations 提供一个内联表单集

问题

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

【问题讨论】:

    标签: django autocomplete django-forms


    【解决方案1】:

    这个问题看起来很简单,但正确的回答会涉及多个答案。

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

    自动完成

    这是最简单的部分。您可以使用 select2jqueryui autocomplete 之类的插件以及可以找到类似用户的视图

    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)
    

    此视图与默认的 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__ 替换 id,这简化了 javascript 以获得更好的可维护性,但我没有找到一种方法来分解真实形式和空一个。

    查看

    使用inlineformset_factory 并将extra 设置为1(以获取唯一要克隆的隐藏表单)的视图非常标准。也不要忘记为字段participant 使用HiddenInput 小部件

    【讨论】:

      【解决方案2】:

      此插件将帮助您获得所需的自动完成功能:

      https://github.com/millioner/django-ajax-select

      【讨论】:

      • +1 是第一个(也是目前唯一一个)回答的人:)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-06-14
      • 2022-01-11
      • 2014-12-07
      • 2011-09-10
      • 2013-01-19
      • 2023-03-12
      • 2014-09-15
      相关资源
      最近更新 更多