Добавьте кнопку для набора форм django
Я начинаю использовать Django 5 и создаю веб-проект для организации обмена подарками Secret Santa.
Моя проблема заключается в том, что при использовании наборов форм они не являются динамическими, поэтому я не могу создавать переменное количество форм по запросу пользователя.
У меня такая форма:
class ParticipanteForm(forms.ModelForm):
class Meta:
model = Participante
fields = ['nombre', 'email']
ParticipanteFormSet = formset_factory(ParticipanteForm)
Эта модель:
class Participante(models.Model):
sorteo = models.ForeignKey(Sorteo, related_name='participantes', on_delete=models.CASCADE)
nombre = models.CharField(max_length=100)
email = models.EmailField()
А это представление, в котором я отображаю формы и сохраняю данные:
def crear_sorteo(request):
sorteo_form = SorteoForm(request.POST or None)
ParticipanteFormSet = formset_factory(ParticipanteForm, extra=3)
participante_formset = ParticipanteFormSet(request.POST or None)
context = {
'sorteo_form': sorteo_form,
'participante_formset': participante_formset,
}
if request.method == 'POST':
if sorteo_form.is_valid():
sorteo = sorteo_form.save() # Save the draw first
if participante_formset.is_valid():
for participante_form in participante_formset:
participante = participante_form.save(commit=False)
participante.sorteo = sorteo # Assign the draw to the participant
participante.save()
return render(request, 'sorteo_realizado.html')
return render(request, 'crear_sorteo.html', context)
Как видите, ParticipanteFormSet = formset_factory(ParticipanteForm, extra=3) в зависимости от того, какое количество extra вы укажете, такое количество форм и будет создано. Но я бы хотел, чтобы в шаблоне:
<body>
<form action="" method="post">
{% csrf_token %}
{{ sorteo_form }}
{{ participante_formset.management_data }}
{{ participante_formset.as_p }}
<input type="submit" value="Realizar sorteo">
</form>
</body>
должна быть кнопка для добавления участника, чтобы пользователь мог ввести столько пользователей, сколько он хочет, с минимальным количеством 3 участника.
Я пытался сделать кнопку, которая постит сообщения и при их получении количество extra
обновляется до +1, но страница перезагружается и данные теряются. Если кто-то знает, как этого добиться, было бы очень полезно, заранее спасибо.
Наконец-то мне удалось решить эту проблему: В шаблоне нужно добавить следующую Django-переменную {{ participante_formset.management_form }}, которая позволяет нам работать с формами, а также добавить кнопку добавления участников, которая будет вызывать JavaScript-функцию, отвечающую за добавление форм с разными ID, чтобы они не оказались с одинаковым именем. В итоге шаблон будет выглядеть следующим образом:
<body>
<style>
.hidden {
display: none;
}
</style>
<form action="" method="post">
{% csrf_token %}
{{ sorteo_form }}
{{ participante_formset.management_form }}
<div id='participante-form-list'>
{% for form in participante_formset %}
<div class='participante-form'>
{{ participante_formset.as_p }}
</div>
{% endfor %}
</div>
<div id='empty-form' class='hidden'>{{ participante_formset.empty_form.as_p }}</div>
<button id='add-more' type='button'>+ participant</button>
<input type="submit" value="Carry out draw">
</form>
</body>
Вместе с JavaScript:
<script>
const addMoreBtn = document.getElementById('add-more')
const totalNewForms = document.getElementById('id_participante-TOTAL_FORMS')
addMoreBtn.addEventListener('click', add_new_form)
function add_new_form(event) {
if (event) {
event.preventDefault()
}
const currentParticipantes = document.getElementsByClassName('participante-form')
let currentFormCount = currentParticipantes.length
const formCopyTarget = document.getElementById('participante-form-list')
const copyEmptyFormEL = document.getElementById('empty-form').cloneNode(true)
copyEmptyFormEL.setAttribute('class', 'participante-form')
copyEmptyFormEL.setAttribute('id', `form-${currentFormCount}`)
const regex = new RegExp('__prefix__', 'g')
copyEmptyFormEL.innerHTML = copyEmptyFormEL.innerHTML.replace(regex,
currentFormCount)
totalNewForms.setAttribute('value', currentFormCount + 1)
formCopyTarget.append(copyEmptyFormEL)
}
</script>
Наконец, в представлении нам просто нужно объявить набор форм с дополнительным значением 0:
ParticipanteFormSet = formset_factory(ParticipanteForm, extra=0)
Я пришел к этому коду благодаря следующему видео, которое, несомненно, будет очень полезным для вас, как и для меня: