OverflowingTheGlass
OverflowingTheGlass

Reputation: 2434

Django Model Form Set POSTs But Does Not Save

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

Answers (2)

Alasdair
Alasdair

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

Zach B.
Zach B.

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

Related Questions