'Django: Display the same form multiple times in the same view
I need to open the same form multiple times while looping trough some items.
This is the form:
class CancelRefundForm(forms.forms.Form):
cancel = forms.BooleanField(label='Check to cancel the refund', required=True ,widget=forms.CheckboxInput(attrs={
'class': 'hidden-checkbox',
'name': 'hiddenCheckBoxName'
}
))
item = forms.IntegerField(
required=True,
widget=forms.NumberInput(attrs={
'class': 'cancel-item-input',
'value': '',
'type': 'hidden'
}),
)
This is the HTML:
<div class="order-items-display">
{% for item in order.orderitem_set.all %}
<div class="single-order-item">
<span >
<a href="{{ item.item.get_absolute_url }}">
<img src="../../../media/{{ item.item.main_image }}" alt="{{ item.item.title }} image">
</a>
</span>
<span class="order-item-details">
<h3><a href="{{ item.item.get_absolute_url }}">
{{ item.item.title }}
{% if item.replica %}
<small>(Replica)</small>
{% endif %}
</a></h3>
<p><strong>Price: </strong>{{ item.old_price }}€</p>
{% if item.quantity > 1 %}
<p><strong>Quantity: </strong>{{ item.quantity }}</p>
<p><strong>Total: </strong>{{ item.get_old_total_price }}€</p>
{% endif %}
{% if order.refund_deadline > nowDate %}
<p><b>The deadline for requesting a refund ends in {{ order.refund_deadline }}(30 days)</b></p>
{% else %}
<p><b>The deadline for requesting a refund ended in {{ order.refund_deadline }}.</b></p>
{% endif %}
<button class="myBtnPri update-cart" data-product="{{item.id}}" data-action="add">
<a class="mySecLink" href="#">
Buy Again
</a>
</button>
{% if item.refund_requested %}
<p><b>Refund requested: </b> {{ item.refund_requested }}</p>
<p><b>Refund granted: </b> {{ item.refund_granted }}</p>
<form action="{% url 'order-details' order.slug %}" method="POST" class="cancel-form">
{% csrf_token %}
{{ cancelForm.item }}
<label for="{{ cancelForm.cancel.id_for_label }}" class="myCheckbox">
{{ cancelForm.cancel }}
<div class="checkbox-box"></div>
<b>Check to cancel the refund</b>
</label>
<button class="myBtnPri cancel-btns" type="submit" data-item="{{ item.item.id }}">
<a class="mySecLink">
Cancel Refund
</a>
</button>
</form>
{% elif item.refund_requested == False and order.refund_deadline > nowDate %}
<button class="myBtnPri refundBtn" data-item="{{ item.item.id }}" data-qty="{{ item.quantity }}">
<a class="mySecLink" href="#">
Refund?
</a>
</button>
{% else %}
<p>Since the refund deadline is over you can no longer refund this Iitem.</p>
{% endif %}
</span>
</div>
{% endfor %}
</div>
In this html I display the items ordered by the user from an old order he made where the user can choose to refund a specific item. If the the user asks for a refund the template will then display a form that asks if the user wants to cancel the refund. If the user decides to refund more than one item from the same order I will have to display the cancelForm one time for each item.
In my views I have:
def order_details_view(request, slug):
dataCart = cartData(request)
cancelForm = CancelRefundForm()
# toRefundItems = len(OrderItem.objects.filter(order = order, refund_requested = True))
# cancelRefundFormSet = formset_factory(CancelRefundForm, extra=toRefundItems)
# formset = cancelRefundFormSet()
order.refund_deadline = order.refund_deadline.astimezone(timezone.utc).replace(tzinfo=None)
if request.method == 'POST':
cancelForm = CancelRefundForm(request.POST)
# formset = cancelRefundFormSet(request.POST)
# CANCEL REFUND FORM LOGIC
if cancelForm.is_valid():
itemId = cancelForm.cleaned_data['item']
orderItem = OrderItem.objects.get(order = order, item = itemId)
if orderItem.refund_requested == True:
orderItem.refund_requested = not cancelForm.cleaned_data['cancel']
orderItem.save()
refund = RefundedItems.objects.get(order = order, item = orderItem)
refund.delete()
order.save()
messages.success(request, f'You successfully canceled the refund of the item {orderItem.id}.')
return redirect(f'/order_details/{order.slug}/')
context = {
'order': order,
'cancelForm': cancelForm,
# 'cancelForm': formset,
'nowDate': datetime.datetime.now(),
'cartItems': dataCart['cartItems'],
}
return render(request, 'users/order_details.html', context)
As you can see by the comments I tried to use formset_factory, but it did not work because I needed to open more than one form. And the way I have above its also not working properly. The multiple forms are displayed in the template but when I check the box from any form it just updates the first one.
Should I create another view and template to deal with this using formset's? Or am I missing something?
Thanks
Solution 1:[1]
To anyone that has the same question, I decided to make one form for each item I needed using Javascript then I displayed it in the template and connected the form to a new view that only handles the cancel refund form's information.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Stephane-Gon |
