Атрибут имени поля ввода идентичный modelform
Я пытаюсь просмотреть модель PendingRequest
и проверить каждый запрос пользователя и одобрить или отклонить запрос пользователя для каждого экземпляра. Я использую ModelForm для отображения формы, однако, часть, которая вызывает проблему, заключается в том, что радиокнопка, на которую нужно нажать, чтобы одобрить или отклонить, не имеет общего входного имени attribue
вот мой шаблон
<form method="post">
{% csrf_token %}
<table>
<thead>
<tr>
<th>Book Title</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{% for book in books %}
<tr>
<td>{{ book.book.title }}</td>
<td>
<input type="radio" name="{{ book.id }}" value="approved"> Approve
<input type="radio" name="{{ book.id }}" value="not_approved"> Decline
</td>
</tr>
{% endfor %}
</tbody>
</table>
<button type="submit">Update</button>
</form>
Итак, что я хочу достичь, это заменить
<input type="radio" name="{{ book.id }}" value="approved">
и <input type="radio" name="{{ book.id }}" value="not_approved">
следующим образом, чтобы при отображении каждый цикл имел одинаковый атрибут name, но разные значения
<form method="post">
{% csrf_token %}
<table>
<thead>
<tr>
<th>Book Title</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{% for book in books %}
<tr>
<td>{{ book.book.title }}</td>
<td>
{% for choice in form.approved %}
{{choice.tag}}
{% endfor %}
{% for choice in form.not_approved %}
{{choice.tag}}
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<button type="submit">Update</button>
</form>
вот мой forms.py
class Approve(forms.ModelForm):
approved = forms.BooleanField(widget=forms.RadioSelect(choices=[(True, 'Approve')]))
not_approved = forms.BooleanField(widget=forms.RadioSelect(choices=[(True, 'Decline')]))
class Meta:
model = PendingRequest
exclude = ["member", "book_request", "book"]
models.py
class PendingRequest(models.Model):
book_request = models.OneToOneField(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)
views.py
def approve(request, pk):
books = PendingRequest.objects.filter(member__id=pk)
if request.method == "POST":
for book in books:
form = Approve(request.POST, instance=book)
if form.is_valid():
book.approve = form.cleaned_data.get(f'approve_{book.id}')
book.save()
return redirect(index)
else:
form = Approve()
return render(request, "books/approve.html", {"form": form, "books": books})
Вы немного усложняете себе задачу...
В этой модели PendingRequest у вас есть два булевых значения. Один для approved
и один для not_approved
. Вам нужна только одна, потому что если approved равно False, то это уже not_approved по определению.
Вы также усложняете себе жизнь, имея два поля с радиокнопками с одной радиокнопкой в каждом поле. Радиокнопки предназначены для множественного выбора, допускается одно значение. Вы можете использовать две радиокнопки для одного поля (флажок часто лучше), но иметь две радиокнопки для двух отдельных полей - это не только плохой HTML, но вы, скорее всего, сможете выбрать оба поля сразу. Если вы дадите им одинаковые имена, чтобы предотвратить это, они не будут привязаны к нужному полю без множества странных пост-постовских заморочек. Это очень муторно. Я бы очень советовал использовать одно поле.
Независимо от того, последуете ли вы этому совету, для нескольких форм одной модели Django может справиться с этой ситуацией с помощью modelformset, что-то вроде...
views.py
PendingRequestFormSet = modelformset_factory(PendingRequest , form = Approve)
#we have to also bring in the book title along with the forms , even though we are not using it in the form,
# so we'll zip up the queryset with the formset.
# We use select_related in the queryset to prevent additional database calls in the template when the title gets evaluated
pending_requests = PendingRequest.objects.filter(member__id=pk).select_related('book')
formset = PendingRequestFormSet(queryset=pending_requests))
pending_requests_and_formset = zip(queryset, formset)
...
return render(request, "books/approve.html", {"form": form, "books": books, 'pending_requests_and_formset', pending_requests_and_formset })
template.html
...
<form method="post">
{{ formset.management_form }}
{% for request, form in pending_requests_and_formset %}
<td>{{request.book.title}}</td>
<td>{{ form }}</td>
{% endfor %}
</form>