'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