Modelformset update multiple instance of model

I am trying to update multiple instance of a model using modelformset_factory to render out the said instances im my forms at one but it doesn't work.

views.py:

def approve(request,pk):
    user = User.objects.get(id=pk)
    requests = PendingRequest.objects.filter(member=user)
    RequestFormset = modelformset_factory(PendingRequest, form=Approve ,extra=0)
    if request.method == "POST":
        formset = RequestFormset(request.POST, queryset=requests)
        if formset.is_valid():
            for form in formset:
                form.save()
    else:
        formset = RequestFormset(queryset=requests)
    return render(request, "books/approve.html",{"formset":formset, "users":requests})

forms.py:

class Approve(forms.ModelForm):
    class Meta:
        model = PendingRequest
        exclude = ["member", "book_request", "not_approved"]

models.py:

class PendingRequest(models.Model):
    book_request = models.ForeignKey(BorrowBook, on_delete=models.CASCADE, null=True)
    member = models.ForeignKey(User, on_delete=models.CASCADE, default="", null=True)
    book = models.ForeignKey(Books, on_delete=models.CASCADE, default="", null=True)
    approved = models.BooleanField(default=False)
    not_approved = models.BooleanField(default=False)
    approval_date = models.DateTimeField(auto_now=True, null=True)

template

<body>
  <form method="post" action="{% url 'approve' pk=users.0.member.id %}">
    {% csrf_token %}
    {% for form in formset.management_form %}
      {{form}}
    {% endfor %}
    <table>
      <thead>
        <tr>
          <th>Book Title</th>
          <th>Approved</th>
          <th>Not Approved</th>
        </tr>
      </thead>
      <tbody>
        {% for form in formset %}
          <tr>
            <td>{{ form.book }}</td>
            <td>{{ form.approved }}</td>
          </tr>
        {% endfor %}
      </tbody>
    </table>
    <button type="submit">Update</button>
  </form>  
</body>

Whenever i click on the submit button in my template, it doesn't post any data to database. Any ideas on how to fix it.

I also want to be able to set not_approved field to true if the user doesn't click on the approved checkbox in template. Any idea on how to go about this will be appreciated

You should use commit=False to temporarily save the instance and also use save_m2m() and to set not_approved field to True if the user doesn't click on the approved checkbox, you can check the cleaned_data of the form for the value of approved.

Try following view:

from django.shortcuts import get_object_or_404

def approve(request,pk):
    user = get_object_or_404(User, id=pk)
    requests = PendingRequest.objects.filter(member=user)
    RequestFormset = modelformset_factory(PendingRequest, form=Approve ,extra=0)
    if request.method == "POST":
        formset = RequestFormset(request.POST, queryset=requests)
        if formset.is_valid():
            for form in formset:
                obj = form.save(commit=False)
                if not form.cleaned_data.get('approved'):
                    obj.not_approved = True
                obj.save()
            formset.save_m2m()
    else:
        formset = RequestFormset(queryset=requests)
    return render(request, "books/approve.html",{"formset":formset, "users":requests})

Note: It is better to use get_object_or_404() instead of get() as it calls get() on a given model manager, but it raises Http404 instead of the model's DoesNotExist exception.

Back to Top