How to write a POST method to an a tag in Django

Viewed 2072

I am trying to write a POST method an "a" tag href but it is not working

I was successful writing it in another page to select from an option but I am trying to implement it in an a href but it is not working

<form method="POST" action="{{ item.get_add_to_cart_url }}">
{% csrf_token %}
<a href="{% url 'core:add-to-cart' order_item.item.slug %}"><i class="fas fa-plus ml-2"></a></i>
</form>

This is the HTML that I am trying to implement the same logic for which is working perfectly

                            {% csrf_token %}
                            <input class="btn btn-primary btn-md my-2 p" type="submit" value="Add to cart">

                            {% if object.variation_set.all %}

                            {% if object.variation_set.sizes %}
                        <select class="form-control" name="size">
                            {% for items in object.variation_set.sizes %}
                            <option value="{{ items.title|lower }}">{{ items.title|capfirst }}</option>
                            {% endfor %}                      
                        </select>
                        {% endif %}
                        {% endif %}

This is the views:


@login_required
def add_to_cart(request, slug):
    item = get_object_or_404(Item, slug=slug)
    order_item_qs = OrderItem.objects.filter(
        item=item,
        user=request.user,
        ordered=False
    )
    print(item)
    print(order_item_qs)
    item_var = []  # item variation
    if request.method == 'POST':
        for items in request.POST:
            key = items
            val = request.POST[key]
            try:
                v = Variation.objects.get(
                    item=item,
                    category__iexact=key,
                    title__iexact=val
                )
                item_var.append(v)
            except:
                pass

        if len(item_var) > 0:
            for items in item_var:
                order_item_qs = order_item_qs.filter(
                    variation__exact=items,
                )

    if order_item_qs.exists():
        order_item = order_item_qs.first()
        order_item.quantity += 1
        order_item.save()
    else:
        order_item = OrderItem.objects.create(
            item=item,
            user=request.user,
            ordered=False
        )
        order_item.variation.add(*item_var)
        order_item.save()

    order_qs = Order.objects.filter(user=request.user, ordered=False)
    if order_qs.exists():
        order = order_qs[0]
        # check if the order item is in the order
        if not order.items.filter(item__id=order_item.id).exists():
            order.items.add(order_item)
            messages.info(request, "This item quantity was updated.")
            return redirect("core:order-summary")
    else:
        ordered_date = timezone.now()
        order = Order.objects.create(
            user=request.user, ordered_date=ordered_date)
        order.items.add(order_item)
        messages.info(request, "This item was added to cart.")
        return redirect("core:order-summary")

Is this the best way to use a Post method?

2 Answers

Your form is not submitting anything, it's just an anchor with an href. Notice how the working code has an input of type submit.

There are many ways you can solve it, I propose two:

  1. Add an input or button of type submit.

<input class="btn btn-primary btn-md my-2 p" type="submit" value="Add to cart">

  1. Set a name attribute on the form, and call document.name.submit() when the link is clicked.

<form name="myForm">
...
<a onClick="document.myForm.submit()">...</a>
</form>

You can learn more about the a and form elements here and here

a tags back to the time the web was literally a web with pages linked to each other by hyperlinks. POST is an HTTP concept and when it comes to HTML it is only possible by using "form submission".

When you are using an HTML form, you make the browser always send the request to the same URL (i.e. action). When a browser opens a page containing a form there are several ways for the form to be submitted:

  1. In case the form contains at least an input element with type equal to 'submit', when the user clicks on the submit button the form gets submitted and the request is sent to the server,
  2. User press enter in existing input elements within the form which again causes the form to be submitted.

The method attribute in the form element only affects the way browser works when a form is submitted. a elements do not interact with their surrounding form and the a element inside the form works just like an a element outside the form. The a element you've put inside the form only causes the browser to navigate to its href regardless of the containing form or its method attribute.

Now to answer your question

Is this the best way to use a Post method?

The correct way of using a post method is any of these ways:

  1. By having a form with its method set to POST and with some input elements inside it which contain data or user input,
  2. By doing javascript, in your case maybe on the onclick action of you a elements, to make specific POST requests. You can find a canonical guide here.
  3. Or as WorkShoft said, set a name attribute on the form, and call document.[name].submit() when the link is clicked.
Related