Set declined to True if approved is False
Question:
I am working on a project that allows student to apply to borrow book from a library and then the librarian decides to approve or decline the request.
models.py
class PendingRequest(models.Model):
book_request = models.ForeignKey(Borrow, on_delete=models.CASCADE, null=True)
member = models.ForeignKey(User, on_delete=models.CASCADE, default=None, null=True)
book = models.ForeignKey(Books, on_delete=models.CASCADE, default=None, null=True)
approved = models.BooleanField(default=False)
declined = models.BooleanField(default=False)
approval_date = models.DateTimeField(auto_now=True, null=True)
I am using a modelformset_factory
to render out the form to update multiple instance of the above model. What i want to achieve is to be able to set declined
field to True and approved
to False whenever the librarian doesn’t approve the request
views.py
def approve(request, pk):
member = get_object_or_404(User, id=pk)
pending_requests = PendingRequest.objects.filter(member=member)
PendingRequestFormSet = modelformset_factory(
PendingRequest, form=ApproveForm, extra=0
)
if request.method == "POST":
formset = PendingRequestFormSet(request.POST, queryset=pending_requests)
approved = request.POST.get(formset.prefix + "-approved")
if formset.is_valid():
instances = formset.save(commit=False)
for instance in instances:
instance.book_request = instance.book_request
instance.member = instance.member
instance.book = instance.book
instance.save()
else:
formset = PendingRequestFormSet(queryset=pending_requests)
context = {"formset": formset, "member": member}
return render(request, "books/approve.html", context)
form.py
class ApproveForm(forms.ModelForm):
approved = forms.BooleanField(required=False)
class Meta:
model = PendingRequest
fields = [
"approved",
"book",
]
template
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Approve Request</title>
</head>
<body>
<h1>Update Pending Requests for {{ member.username }}</h1>
<form method="post">
{% csrf_token %}
{{ formset.management_form }}
<table>
<thead>
<tr>
<th>Book</th>
<th>Approved</th>
</tr>
</thead>
<tbody>
{% for form in formset %}
<tr>
<td>{{form.book}}</td>
<td>{{form.approved}}</td>
</tr>
{% endfor %}
</tbody>
</table>
<input type="submit" value="Update" />
</form>
<style>
select {
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
background: transparent;
border: none;
font-size: 15px;
}
select {
pointer-events: none;
}
</style>
</body>
</html>
Answers:
Our friend in comments meant that approved
and declined
fields are mutually exclusive. You only need one of them to indicate that specific status.
class PendingRequest(models.Model):
...
approved = models.BooleanField(default=False)
declined = models.BooleanField(default=False)
...
Related to you question. Form is not validating because id field is required, so add them in:
forms.py
class ApproveForm(forms.ModelForm):
approved = forms.BooleanField(required=False)
class Meta:
model = PendingRequest
fields = [
"id",
"approved",
"book",
]
widgets = {
"id": forms.HiddenInput()
}
and also in templates.py
...
<tbody>
{% for form in formset %}
<tr>
{{form.id}}
<td>{{form.book}}</td>
<td>{{form.approved}}</td>
</tr>
{% endfor %}
</tbody>
...
and views.py
if request.method == "POST":
formset = PendingRequestFormSet(request.POST, queryset=pending_requests)
for form in formset:
if form.is_valid():
if form.cleaned_data['approved']:
form.save()
That will set approved
field to True
or False
on update click. If you want to maintain declined
field then just add to forms.pt
as a hidden field using the same process, although I would recommend to remove it.
I am working on a project that allows student to apply to borrow book from a library and then the librarian decides to approve or decline the request.
models.py
class PendingRequest(models.Model):
book_request = models.ForeignKey(Borrow, on_delete=models.CASCADE, null=True)
member = models.ForeignKey(User, on_delete=models.CASCADE, default=None, null=True)
book = models.ForeignKey(Books, on_delete=models.CASCADE, default=None, null=True)
approved = models.BooleanField(default=False)
declined = models.BooleanField(default=False)
approval_date = models.DateTimeField(auto_now=True, null=True)
I am using a modelformset_factory
to render out the form to update multiple instance of the above model. What i want to achieve is to be able to set declined
field to True and approved
to False whenever the librarian doesn’t approve the request
views.py
def approve(request, pk):
member = get_object_or_404(User, id=pk)
pending_requests = PendingRequest.objects.filter(member=member)
PendingRequestFormSet = modelformset_factory(
PendingRequest, form=ApproveForm, extra=0
)
if request.method == "POST":
formset = PendingRequestFormSet(request.POST, queryset=pending_requests)
approved = request.POST.get(formset.prefix + "-approved")
if formset.is_valid():
instances = formset.save(commit=False)
for instance in instances:
instance.book_request = instance.book_request
instance.member = instance.member
instance.book = instance.book
instance.save()
else:
formset = PendingRequestFormSet(queryset=pending_requests)
context = {"formset": formset, "member": member}
return render(request, "books/approve.html", context)
form.py
class ApproveForm(forms.ModelForm):
approved = forms.BooleanField(required=False)
class Meta:
model = PendingRequest
fields = [
"approved",
"book",
]
template
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Approve Request</title>
</head>
<body>
<h1>Update Pending Requests for {{ member.username }}</h1>
<form method="post">
{% csrf_token %}
{{ formset.management_form }}
<table>
<thead>
<tr>
<th>Book</th>
<th>Approved</th>
</tr>
</thead>
<tbody>
{% for form in formset %}
<tr>
<td>{{form.book}}</td>
<td>{{form.approved}}</td>
</tr>
{% endfor %}
</tbody>
</table>
<input type="submit" value="Update" />
</form>
<style>
select {
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
background: transparent;
border: none;
font-size: 15px;
}
select {
pointer-events: none;
}
</style>
</body>
</html>
Our friend in comments meant that approved
and declined
fields are mutually exclusive. You only need one of them to indicate that specific status.
class PendingRequest(models.Model):
...
approved = models.BooleanField(default=False)
declined = models.BooleanField(default=False)
...
Related to you question. Form is not validating because id field is required, so add them in:
forms.py
class ApproveForm(forms.ModelForm):
approved = forms.BooleanField(required=False)
class Meta:
model = PendingRequest
fields = [
"id",
"approved",
"book",
]
widgets = {
"id": forms.HiddenInput()
}
and also in templates.py
...
<tbody>
{% for form in formset %}
<tr>
{{form.id}}
<td>{{form.book}}</td>
<td>{{form.approved}}</td>
</tr>
{% endfor %}
</tbody>
...
and views.py
if request.method == "POST":
formset = PendingRequestFormSet(request.POST, queryset=pending_requests)
for form in formset:
if form.is_valid():
if form.cleaned_data['approved']:
form.save()
That will set approved
field to True
or False
on update click. If you want to maintain declined
field then just add to forms.pt
as a hidden field using the same process, although I would recommend to remove it.