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 theapproved
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 ofget()
as it callsget()
on a given model manager, but it raisesHttp404
instead of the model'sDoesNotExist
exception.