I’m developing a Django page where a user fills out a lottery form. This data is stored in a MySQL database. Part of the functionality of the page is that the user can retrieve the form with the lottery data already entered to add more, modify some, or rerun the lottery without needing to re-enter all the data.
Now, for this purpose, I have these forms that I am using to retrieve the lottery, add participants, add lottery data, etc…
class SorteoForm(forms.ModelForm):
class Meta:
model = Sorteo
fields = ['organizer', 'celebration_date', 'budget']
class ExclusionForm(forms.Form):
participants_to_exclude = forms.CharField(label='Participants to exclude', max_length=100)
class SorteoRecuperadorForm(forms.Form):
recuperator_lottery = forms.CharField(label='Lottery code', max_length=50, required=False)
class ParticipanteExclusionForm(forms.Form):
name = forms.CharField(label='', max_length=100, widget=forms.TextInput(attrs={'placeholder': 'Name'}))
email = forms.EmailField(label='', max_length=100, widget=forms.EmailInput(attrs={'placeholder': 'Email'}))
exclusions = forms.CharField(label='', max_length=100, required=False, widget=forms.TextInput(attrs={'placeholder': 'Exclusions'}))
ParticipanteExclusionFormSet = formset_factory(ParticipanteExclusionForm)
ParticipanteFormSet = formset_factory(ParticipanteForm)
ExclusionFormSet = formset_factory(ExclusionForm)
The data control for these forms, both to rerun the lottery and to retrieve the data, is done through this method:
def recover_lottery(request):
lottery_form = SorteoForm(request.POST or None)
ParticipanteExclusionFormSet = formset_factory(ParticipanteExclusionForm, extra=0)
participant_formset = ParticipanteExclusionFormSet(request.POST or None, prefix='participant')
recuperator_form = SorteoRecuperadorForm(request.POST or None)
lottery = None
participants = None
if request.method == 'POST':
if recuperator_form.is_valid():
# Retrieve the lottery and participants
lottery = Sorteo.objects.filter(recover_lottery=recuperator_form.cleaned_data['recuperator_lottery']).first()
if lottery:
participants = lottery.participants.all()
elif lottery_form.is_valid() and participant_formset.is_valid():
# Logic to save the new lottery
context = {
'lottery_form': lottery_form,
'participant_formset': participant_formset,
'recuperator_form': recuperator_form,
'lottery': lottery,
'participants': participants,
}
return render(request, 'index/recover_lottery.html', context)
All of this is managed in the following template:
<form action="" method="post" onsubmit="return validateForm()">
{% csrf_token %}
{{ recuperator_form }}
<button type="submit" name="recover_lottery">Recover</button>
</form>
{% if lottery %}
<h2>Recovered Lottery</h2>
<form action="" method="post" class="completeForm">
{% csrf_token %}
<div class="lotteryForm">
<div>
<label for="organizer">Organizer Name</label>
{{ lottery_form.organizer }}
</div>
<div>
<label for="celebration_date">Celebration Date</label>
{{ lottery_form.celebration_date }}
</div>
<div>
<label for="budget">Budget</label>
{{ lottery_form.budget }}
</div>
</div>
{{ participant_formset.management_form }}
{{ exclusion_formset.management_form }}
<div id='participant-form-list'>
{% for form in participant_formset %}
<div class='participant-form'>
{{ participant_formset.as_p }}
</div>
{% endfor %}
</div>
<div id='empty-form-participant' class='hidden'>{{ participant_formset.empty_form.as_p }}</div>
<div>
<button class="formButtons addButton" id='add-more' type='button'>Add Participant</button>
<input class="formButtons doneButton" name="" type="submit" value="Run Lottery">
</div>
</form>
{% endif %}
With its corresponding JavaScript:
<script>
function validateForm() {
var field = document.getElementById('id_recuperator_lottery').value;
if (field.trim() == '') {
alert('Please complete the field');
return false;
}
return true;
}
/* Logic to load the data into the form */
function start() {
document.getElementById("id_organizer").value = "{{ lottery.organizer }}"
document.getElementById("id_celebration_date").value = "{{ lottery.celebration_date }}"
document.getElementById("id_budget").value = "{{ lottery.budget }}"
};
start()
/* Complete logic for the run lottery form */
const addMoreBtn = document.getElementById('add-more');
const totalNewFormsParticipant = document.getElementById('id_participant-TOTAL_FORMS');
addMoreBtn.addEventListener('click', add_new_form);
for (let index = 0; index < 3; index++) { addMoreBtn.click() } function add_new_form(event) {
if (event) {
event.preventDefault();
} const currentParticipants = document.getElementsByClassName('participant-form'); let
currentFormCountParticipants = currentParticipants.length; const
formCopyTarget = document.getElementById('participant-form-list'); const
copyEmptyFormELParticipant = document.getElementById('empty-form-participant').cloneNode(true);
copyEmptyFormELParticipant.setAttribute('class', 'participant-form');
copyEmptyFormELParticipant.setAttribute('id', `form-${currentFormCountParticipants}`); const regex = new
RegExp('__prefix__', 'g');
copyEmptyFormELParticipant.innerHTML = copyEmptyFormELParticipant.innerHTML.replace(regex,
currentFormCountParticipants); totalNewFormsParticipant.setAttribute('value', currentFormCountParticipants + 1);
formCopyTarget.append(copyEmptyFormELParticipant);
} </script>
When executing this within the form, I get the errors:
(Hidden field TOTAL_FORMS) *This field is required.
(Hidden field INITIAL_FORMS) *This field is required.
Tests and Hypotheses
- Deactivating the if statements in the template eliminates the error until the lottery code to be retrieved is entered.
- Leaving only the lottery data form and not retrieving participants/exclusions, the error does not appear.
- Check if the TOTAL_FORMS and INITIAL_FORMS fields exist and are rendered correctly.
- In the template where the user enters the lottery data for the first time, the error does not appear.
- Perhaps the issue is having two forms in the same view; I tried putting a button with a different name to control it in the view.