表单数据未绑定在 Django 中动态添加的内联表单集中
Form data is not bound in dynamically added inline formset in Django
我有一个关于在 Django 中验证动态添加的内联表单集的问题。似乎我在实施中遗漏了一些东西。
这是我的案例:
我的项目是一个团队管理平台。一个团队称为 Crew,可以有多个时间表。每个时间表可以有多个班次。请看看我的代码。目前,如果所有字段都有效,我可以创建一个时间表,其中包含几个动态添加的表单集表单,如果所有字段都有效的话。
如果不是,则不显示 Shift 表单的错误,并再次填充初始数据。发送 POST 请求后,班次表格的数据似乎未绑定(因为 form.is_bound() 为 false)。此外,在 POST 请求之后,不会再次填充 Shift 表单的数据。
您认为造成这种行为的原因是什么?我是否必须覆盖 is_valid 函数?我不知道,因为它看起来功能正常 - 数据只是没有正确绑定到新表单。
Views.py
def schedule_add(request, crew_id):
if request.method == "GET":
form = ScheduleForm()
ShiftFormSet = formset_factory(ShiftForm)
return render(request, 'schedule_add2.html', {'form': form, 'formset': ShiftFormSet, 'title':"Zeitplan hinzufügen"})
elif request.method == "POST":
form = ScheduleForm(request.POST)
numberOfShifts = int(request.POST['form-TOTAL_FORMS'])
ShiftFormSet = formset_factory(ShiftForm, extra=numberOfShifts)
shift_formset = ShiftFormSet(request.POST, prefix='form')
print(request.POST)
if form.is_valid() and shift_formset.is_valid():
schedule = Schedule()
schedule.name = form.cleaned_data.get('name')
schedule.crew = Crew.objects.get(pk=crew_id)
schedule.location = form.cleaned_data.get('location')
schedule.subperiod = form.cleaned_data.get('sub_period')
schedule.save()
for shift_form in shift_formset:
if shift_form.is_valid():
shift = Shift()
shift.min_user_count = shift_form.cleaned_data.get('min_user_count')
shift.max_user_count = shift_form.cleaned_data.get('max_user_count')
shift.start_datetime = shift_form.cleaned_data.get('start_time')
shift.end_datetime = shift_form.cleaned_data.get('end_time')
shift.schedule = schedule
shift.save()
messages.success(request, 'Zeitplan & Schichten angelegt.')
return redirect('shifter:crew_view', crew_id=crew_id)
else:
messages.error(request, 'Fehler')
return render(request, 'schedule_add2.html', {'form': form, 'formset': ShiftFormSet, 'title':"Zeitplan hinzufügen"})
else:
return redirect('shifter:index')
forms.py
class ScheduleForm(forms.ModelForm):
name = forms.CharField(max_length=30, required=True, help_text='', label="Name")
sub_period = forms.ModelChoiceField(queryset=SubPeriod.objects.all(), empty_label=None, label="Tag")
location = forms.ModelChoiceField(queryset=Location.objects.all(), empty_label=None, label="Einsatzort")
class Meta:
model = Schedule
fields = ('name', 'sub_period', 'location',)
class ShiftForm(forms.ModelForm):
min_user_count = forms.IntegerField(required=True, help_text='', label="Min Count", initial=2)
max_user_count = forms.IntegerField(required=True, help_text='', label="Max Count", initial=4)
start_time = forms.DateTimeField(required=True, help_text='', label="Shift start", initial=datetime.now)
end_time = forms.DateTimeField(required=True, help_text='', label="Shift end", initial=datetime.now)
class Meta:
model = Shift
fields = ('start_time','end_time','min_user_count','max_user_count',)
模板
<form method="post">
{% csrf_token %}
{% if form.non_field_errors %}
<div class="alert alert-danger" role="alert">
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</div>
{% endif %}
{% for field in form.visible_fields %}
{{ field.label_tag }}
{% if form.is_bound %}
{% if field.errors %}
{% render_field field class="form-control is-invalid" %}
{% for error in field.errors %}
<div class="invalid-feedback">
{{ error }}
</div>
{% endfor %}
{% else %}
{% render_field field class="form-control is-valid" %}
{% endif %}
{% else %}
{% render_field field class="form-control" %}
{% endif %}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
{% endfor %}
<h2 class="mt-5">Shifts</h2>
<table class="table">
{{ formset.management_form }}
{% for form in formset.forms %}
{% if forloop.first %}
<thead>
<tr>
{% for field in form.visible_fields %}
<th>{{ field.label|capfirst }}</th>
{% endfor %}
<th></th>
</tr>
</thead>
{% endif %}
<tr class="formset_row">
{% for field in form.visible_fields %}
<td>
{# Include the hidden fields in the form #}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{% if form.is_bound %}
{% if form.errors %}
{% render_field field class="form-control is-invalid" %}
{% for error in form.errors %}
<div class="invalid-feedback">
{{ error }}
</div>
{% endfor %}
{% else %}
{% render_field field class="form-control is-valid" %}
{% endif %}
{% else %}
{% render_field field class="form-control" %}
{% endif %}
</td>
{% endfor %}
<td></td>
</tr>
{% endfor %}
</table>
<button type="submit" class="btn btn-primary">Save</button>
</form>
提前致谢,
克里斯托弗
您将 class、ShiftFormSet
返回到模板(在代码的 third-from-last 行)而不是实例 shift_formset
。
我有一个关于在 Django 中验证动态添加的内联表单集的问题。似乎我在实施中遗漏了一些东西。
这是我的案例: 我的项目是一个团队管理平台。一个团队称为 Crew,可以有多个时间表。每个时间表可以有多个班次。请看看我的代码。目前,如果所有字段都有效,我可以创建一个时间表,其中包含几个动态添加的表单集表单,如果所有字段都有效的话。
如果不是,则不显示 Shift 表单的错误,并再次填充初始数据。发送 POST 请求后,班次表格的数据似乎未绑定(因为 form.is_bound() 为 false)。此外,在 POST 请求之后,不会再次填充 Shift 表单的数据。 您认为造成这种行为的原因是什么?我是否必须覆盖 is_valid 函数?我不知道,因为它看起来功能正常 - 数据只是没有正确绑定到新表单。
Views.py
def schedule_add(request, crew_id):
if request.method == "GET":
form = ScheduleForm()
ShiftFormSet = formset_factory(ShiftForm)
return render(request, 'schedule_add2.html', {'form': form, 'formset': ShiftFormSet, 'title':"Zeitplan hinzufügen"})
elif request.method == "POST":
form = ScheduleForm(request.POST)
numberOfShifts = int(request.POST['form-TOTAL_FORMS'])
ShiftFormSet = formset_factory(ShiftForm, extra=numberOfShifts)
shift_formset = ShiftFormSet(request.POST, prefix='form')
print(request.POST)
if form.is_valid() and shift_formset.is_valid():
schedule = Schedule()
schedule.name = form.cleaned_data.get('name')
schedule.crew = Crew.objects.get(pk=crew_id)
schedule.location = form.cleaned_data.get('location')
schedule.subperiod = form.cleaned_data.get('sub_period')
schedule.save()
for shift_form in shift_formset:
if shift_form.is_valid():
shift = Shift()
shift.min_user_count = shift_form.cleaned_data.get('min_user_count')
shift.max_user_count = shift_form.cleaned_data.get('max_user_count')
shift.start_datetime = shift_form.cleaned_data.get('start_time')
shift.end_datetime = shift_form.cleaned_data.get('end_time')
shift.schedule = schedule
shift.save()
messages.success(request, 'Zeitplan & Schichten angelegt.')
return redirect('shifter:crew_view', crew_id=crew_id)
else:
messages.error(request, 'Fehler')
return render(request, 'schedule_add2.html', {'form': form, 'formset': ShiftFormSet, 'title':"Zeitplan hinzufügen"})
else:
return redirect('shifter:index')
forms.py
class ScheduleForm(forms.ModelForm):
name = forms.CharField(max_length=30, required=True, help_text='', label="Name")
sub_period = forms.ModelChoiceField(queryset=SubPeriod.objects.all(), empty_label=None, label="Tag")
location = forms.ModelChoiceField(queryset=Location.objects.all(), empty_label=None, label="Einsatzort")
class Meta:
model = Schedule
fields = ('name', 'sub_period', 'location',)
class ShiftForm(forms.ModelForm):
min_user_count = forms.IntegerField(required=True, help_text='', label="Min Count", initial=2)
max_user_count = forms.IntegerField(required=True, help_text='', label="Max Count", initial=4)
start_time = forms.DateTimeField(required=True, help_text='', label="Shift start", initial=datetime.now)
end_time = forms.DateTimeField(required=True, help_text='', label="Shift end", initial=datetime.now)
class Meta:
model = Shift
fields = ('start_time','end_time','min_user_count','max_user_count',)
模板
<form method="post">
{% csrf_token %}
{% if form.non_field_errors %}
<div class="alert alert-danger" role="alert">
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</div>
{% endif %}
{% for field in form.visible_fields %}
{{ field.label_tag }}
{% if form.is_bound %}
{% if field.errors %}
{% render_field field class="form-control is-invalid" %}
{% for error in field.errors %}
<div class="invalid-feedback">
{{ error }}
</div>
{% endfor %}
{% else %}
{% render_field field class="form-control is-valid" %}
{% endif %}
{% else %}
{% render_field field class="form-control" %}
{% endif %}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
{% endfor %}
<h2 class="mt-5">Shifts</h2>
<table class="table">
{{ formset.management_form }}
{% for form in formset.forms %}
{% if forloop.first %}
<thead>
<tr>
{% for field in form.visible_fields %}
<th>{{ field.label|capfirst }}</th>
{% endfor %}
<th></th>
</tr>
</thead>
{% endif %}
<tr class="formset_row">
{% for field in form.visible_fields %}
<td>
{# Include the hidden fields in the form #}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{% if form.is_bound %}
{% if form.errors %}
{% render_field field class="form-control is-invalid" %}
{% for error in form.errors %}
<div class="invalid-feedback">
{{ error }}
</div>
{% endfor %}
{% else %}
{% render_field field class="form-control is-valid" %}
{% endif %}
{% else %}
{% render_field field class="form-control" %}
{% endif %}
</td>
{% endfor %}
<td></td>
</tr>
{% endfor %}
</table>
<button type="submit" class="btn btn-primary">Save</button>
</form>
提前致谢, 克里斯托弗
您将 class、ShiftFormSet
返回到模板(在代码的 third-from-last 行)而不是实例 shift_formset
。