質問は非常に単純に見えますが、適切な回答にはいくつかの回答が含まれます。
jQueryを使用して、ソリューションを1つずつ示します。
オートコンプリート
これは単純な部分です。select2やjqueryuiオートコンプリートなどのプラグインと、次のようなユーザーを検索するビューを使用できます。
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)
このビューは、デフォルトのjQueryUIオートコンプリートプラグインと互換性があります
動的フォームセット
これはトリッキーなものです。重要なのは、とを利用することmanagement_form
ですform.DELETE
。これが私の解決策です:
- 参加者用のインラインフォームセットを使用します(追加のフォームが1つあります)
- 印刷する
management_form
- 非表示の空のフォーム(余分なフォーム)を複製してインクリメントすることにより、オートコンプリート選択後にjQueryを使用してフォーム行を追加します
id_form-TOTAL_FORMS
- 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
インスタンスを使用してIDを置き換えることもできることは知っています__prefix__
が、これによりJavaScriptが簡素化され、保守性が向上しますが、コードを実際の形式と空の形式の間で因数分解する方法が見つかりませんでした。
意見
inlineformset_factory
ビューは、1に設定して使用するのはかなり標準的ですextra
(複製する唯一の非表示のフォームを取得するため)。HiddenInput
また、フィールドにウィジェットを使用することを忘れないでくださいparticipant