Reputation: 2434
I have a Django site built on a model formset (forms.py
). The model formset is picked up by my view (views.py
). The view is rendered in my template (alerts.html
). The user sees a list of alerts with entity and logic populated. They must enter a comment on one or more forms in the formset and then click the submit button to post the one or more forms to the DB. When the submit button is clicked currently, the page refreshes and a successful POST (200) displays in runserver
, but the data is not saved to the DB. formset.errors
shows that comment
is required for each field, not just the form that was changed.
I tried adding if formset.has_changed():
prior to calling formset.save()
, but the problem persisted.
How should I alter my project to allow the model formset to be saved appropriately?
EDIT: I migrated blank=True
for comment. Now when the submit button is clicked, the data is saved. However, the comment text (and the rest of the form) remains in the table in the template. When submit is clicked again, the comment text remains and entity
and logic
are replaced by blanks.
forms.py
class AlertForm(ModelForm):
class Meta:
model = Alert
fields = [
'comment'
]
AlertFormSet = modelformset_factory(Alert, extra=0, form=AlertForm)
views.py
def alerts(request):
newAlerts = Alert.objects.filter(comment='')
formset = AlertFormSet(request.POST or None, queryset=newAlerts)
context = {'formset':formset}
if request.method == 'POST':
formset = formset
if formset.is_valid():
formset.save()
else:
formset = formset
print(formset.errors)
return render(request, 'alerts/alerts.html', context)
alerts.html
<form method='POST' action=''>
{{ formset.management_form }}
{% csrf_token %}
<input name="submit" value="Submit" id="submit-id-submit" type="submit">
{% for form in formset %}
{% for hidden_field in form.hidden_fields %}
{{ hidden_field }}
{% endfor %}
{% endfor %}
<table>
<thead>
<tr>
<th>Entity</th>
<th>Logic</th>
<th>Comment</th>
</tr>
</thead>
<tbody>
{% for form in formset %}
<tr>
<td>{{ form.instance.entity }}</td>
<td>{{ form.instance.logic }}</td>
<td>{{ form.comment }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</form>
Upvotes: 2
Views: 2863
Reputation: 308799
The formset is invalid because you are not submitting the values for the entity
or logic
fields. You would see this if you printed formset.errors
in your view or included the form errors in the template.
Since you don't want entity
or logic
to be editable, you should not include these in the formset's fields:
class AlertForm(ModelForm):
class Meta:
model = Alert
fields = [
'comment',
]
Since you are defining fields
in the form, you shouldn't need to include exclude
when you call modelformset_factory
.
AlertFormSet = modelformset_factory(Alert, extra=0, form=AlertForm)
Upvotes: 2
Reputation: 693
Try looping over the data in the formset like this
if request.method == 'POST':
formset = formset
if formset.is_valid():
for form in formset:
cleaned_data = form.cleaned_data
entity = cleaned_data.get('entity')
logic = cleaned_data.get('logic')
comment = cleaned_data.get('comment')
# create a new Alert object here
alert = Alert(entity=entity, logic=logic, comment=comment)
alert.save()
Upvotes: 0