How to make forms support PUT or DELETE method?

I know that Django supports GET and POST methods in forms, but how can I make some forms use PUT or DELETE methods?

For example, this form which redirects to listing-delete view.
templates\partials\listings\detail\head.html:

{# Head #}
{% if request.user.is_authenticated and listing.poster == request.user %}
  <div class="d-flex justify-content-between mb-3">
    {# 4 Authentication & authorization #}
    <form action="{% url 'listing-delete' listing %}" method="post">
      {# Add DELETE method #}

      {# 3 CSRF tokens #}
      {% csrf_token %}

      <div class="btn-group" role="group">
        <a class="btn btn-secondary fw-semibold" href="{% url 'listing-update' listing %}">Izmeni</a>
        <button class="btn btn-danger fw-semibold" type="submit">Obriši</button>
      </div>
    </form>
  </div>
{% endif %}

realestate\listings\urls.py:

urlpatterns = [
    path("", views.llist, name="listing-list"),
    path("/pretraga", views.search, name="listing-search"),
    path("/<int:listing>", views.detail, name="listing-detail"),

    # 4 Authentication & authorization
    path("/postavka", views.create, name="listing-create"),
    # path("/postavka", login_required(views.create), name="listing-create"),
    path("/izmena/<int:listing>", login_required(views.update), name="listing-update"), # PUT
    path("/brisanje/<int:listing>", login_required(views.delete), name="listing-delete"), # DELETE
    path("/cuvanje/<int:listing>", login_required(views.bookmark), name="listing-bookmark"),
]

delete deletes listing and its terms obviously. No need to explain the inside services.
listings\views.py:

def delete(request: HttpRequest, listing: Listing):
    # 4 Authentication & authorization
    user = CustomUser(request.user)

    # 6 Error handling
    if user == listing.poster:
        terms = listing.terms

        listing_serv.delete(listing)
        terms_serv.delete(terms)

        # 5 Security logging
        logger.info(log_messages.listing_view["delete"], extra={"context": {"user_id": user.pk, "terms_id": terms.pk, "listing_id": listing.pk}})
        return redirect(reverse("listing-detail"))

    # 5 Security logging
    logger.info(log_messages.listing_view["delete__forbidden"], extra={"context": {"listing_id": listing.pk}})
    return HttpResponseForbidden()

A browser will not send a PUT or DELETE verb from an HTTP form. It will only send a GET or POST. (See RFC 1866)

If you want the browser to issue a PUT or DELETE, it must be done through JavaScript.

Ken is right. If you’re curious, there is some movement on getting more than GET and POST natively supported in HTML though: https://triptychproject.org/

I thought Django could have a way to spoof other HTTP methods like laravel?

HTML forms natively only support GET and POST—browsers just ignore PUT or DELETE on a standard .

For traditional Django templates, sticking with method=“POST” in your form and handling the deletion in a standard POST view is the normal, cleanest way to do it.

If you really need actual DELETE/PUT HTTP methods, your best bets are:

HTMX (Easiest): Drop the form and use Obriši.

JS / Fetch: Fire a JavaScript fetch() request with method ‘DELETE’.

Custom Middleware: Use a hidden in your POST form and write custom middleware to override request.method.

Stick to a basic POST view unless you’re using HTMX or an API framework like DRF!

To add to the above:

This is what Laravel does.

You could add this to your form:
<input type="hidden" name="_method" value="PUT">

And then either add a test for this in your view or use custom middleware to alter the method name.

If you alter the method name, I believe that Django won’t automatically parse the body, so you’ll need to do it yourself. (I’m not sure about this either way.)

Also, if you’re using the Django generic CBVs, you’ll need to configure them to allow the new verbs to be used.

(Personally, I consider this a bad idea. Any code submitted to one of my projects doing something like this would be rejected immediately.)