Navigation
Search
|
Dynamic web apps with HTMX, Python, and Django
Wednesday February 12, 2025. 10:00 AM , from InfoWorld
![]() Django is a mature framework that can be combined with HTMX to develop fully interactive web applications without directly coding in JavaScript. To start, you’ll need to install Python 3, then install the Django framework. Once you have those set up in your development environment, you can create a directory and start a new project using the django-admin command: $ mkdir quoteproject $ django-admin startproject quoteproject quoteproject/ $ cd quoteproject It’s also a good practice to set up an alias so $ python refers to the python3 runtime: $ alias python=python3 If you need to access the development server from outside of localhost, you can modify the allowed host settings at quoteproject/settings.py: ALLOWED_HOSTS = ['*'] Note that this allows all incoming requests, so it’s not very secure. You can fine-tune the setting to accept only your client IP. Either way, we can now run the development server: $ python manage.py runserver 3000 If you want to listen for external hosts, use: $ python manage.py runserver 0.0.0.0:3000. If you check the host server, you should see a welcome screen like the one here: The components We’ll build an application that lets us list and create quotes. I’ve used this example in previous articles, as it’s useful for demonstrating server-side application capabilities. It consists of three primary components, which we’ll build with Django and a dash of HTMX: Models Views Routes As a model-view-template (MVT) framework, Django is slightly different from MVC (model-view-controller) frameworks like Express and Spring. But the distinction isn’t hugely important. A Django application’s main jobs of routing requests, preparing a model, and rendering the responses are all handled by well-defined components. Django also ships with built-in persistence, which makes saving data and managing a schema in an SQL database very simple. Our application includes an SQLite database instance, which we‘ll use for development. Now let’s look at the main components. Developing the model in Django We only need a single model for this example, which will handle quotes: // quoteapp/models.py from django.db import models class Quote(models.Model): text = models.TextField() author = models.CharField(max_length=255) from django.db import models This is Django’s ORM syntax for a persistent object called Quote. It contains two fields: a large TextField called text and a 255-length CharField called author. This gives us a lot of power, including the ability to list and perform CRUD operations on Quote objects. Whenever we make changes to the database, we can use Django’s tooling to update the schema: $ python manage.py makemigrations $ python manage.py migrate The makemigrations command creates a new migration file if any schema changes are detected. (These are found in quoteapp/migrations, but you won’t typically need to interact with them directly.) The migrate command applies the changes. Conflicts with schema changes When several people make migration changes and then check them into version control, Django has mechanisms for addressing any version conflicts that may arise. See Django’s migrations documentation to learn more. Constructing the view Next up, let’s consider the view, which accepts a request and prepares the model (if necessary), and hands it off to be rendered as a response. We’ll only need one view, found at quoteapp/views.py: // cat quoteapp/views.py from django.shortcuts import render from django.template.loader import render_to_string from django.http import HttpResponse from.models import Quote def index(request): if request.method == 'POST': text = request.POST.get('text') author = request.POST.get('author') if text and author: new_quote = Quote.objects.create(text=text, author=author) # Render the new quote HTML html = render_to_string('quoteapp/quote_item.html', {'quote': new_quote}) return HttpResponse(html) quotes = Quote.objects.all() return render(request, 'quoteapp/index.html', {'quotes': quotes}) In this view, we import the Quote model and use it to craft a response in the index function. The request argument gives us access to all the information we need coming from the client. If the method is POST, we assemble a new Quote object and use Quote.objects.create() to insert it into the database. As a response, we send back just the markup for the new quote, because HTMX will insert it into the list on the front end. If the method is a GET, we can use Quote.objects.all() to recover the existing set of quotes and send the markup for the whole page at quoteapp/index.html. Django templates with HTMX Quote_item.html and index.html are both templates. They let us take the model provided by the view and construct markup. These reside in a special template path. Here’s the simple quote item template, which renders an item: // quoteapp/templates/quoteapp/quote_item.html {{ quote.text }} - {{ quote.author }} And here’s the main index template: // quoteapp/templates/quoteapp/index.html Quotes {% for quote in quotes %} {{ quote.text }} - {{ quote.author }} {% endfor %} {% csrf_token %} Add Quote /python-django-htmx/quoteproject$ cat quoteapp/urls.py from django.urls import path from. import views urlpatterns = [ path('', views.index, name='index'), ] These templates use the Django template language, which works similarly to Pug or Thymeleaf. Django’s template language lets us use HTML with access to the exposed Quote model. We use the {{ }} and {% %} variables and tags to access variables in Python. For example, we could use {% for quote in quotes %} to set up a loop that iterates over the quotes, exposing a quote variable on each iteration. Because HTMX is simply an extension of HTML, we can use its properties in the Django template just like any other HTML: hx-post indicates this form should be POSTed, and where to send the data. In this case, we’re posting to the index endpoint in views.py. hx-target indicates where to put the response from the server. In this case, we want to append it to the list, because the server will send the new quote item. hx-swap lets us fine-tune exactly how the response is handled. In this case, we stick it beforeend, meaning we want it to be the final element in the list. Routing requests Now we need to tell Django what requests go where. Django uses a project and app concept, where a single project can contain many apps. The basic routing occurs in the project, which was generated by the project creator. Now we’ll add a new route for our application: // quoteproject/urls.py from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('', include('quoteapp.urls')) ] The one we’re interested in is routing the root path (‘’) to the included quoteapp.urls, which we define here: // quoteapp/urls.py from django.urls import path from. import views urlpatterns = [ path('', views.index, name='index'), ] This also tells us where the empty ‘’ path should go, which is to call the index function we saw earlier in views.py. The name argument provides a handle to the path that we can use in links in the project. There’s more information about the path function and URL handling in the Django docs. Run the app We’re almost ready to run and test the application. A final step is to tell Django the quoteapp is part of the quoteproject, which we do in settings.py: // quoteproject/settings.py INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'quoteapp' ] In this case, we’ve added the quoteapp directory to the INSTALLED_APPS array. Now if we run the app with $ python manage.py runserver 3000, we’ll see a simple but functional UI: Conclusion This article demonstrated the basic elements of building a web application using Python, Django, and HTMX. Without much more work, we could use the same routing and endpoint logic to build APIs (consider Django REST). Django is a well-designed and mature framework for Python; it works smoothly and rarely gets in your way. Django is geared toward SQL databases, so it may not be the best choice if you prefer to use a NoSQL database like MongoDB. On the other hand, it makes using SQL data stores very convenient. If you’re a Python developer, Django is a clear winner for building SQL-based, data-driven web applications. For more straightforward RESTful APIs, you might want something more focused like Falcon or Flask. Not surprisingly, the experience of using Python, Django, and HTMX together is comparable to using HTMX with Java and Spring Boot or JavaScript and Express, or C# and.Net. Regardless of the framework or stack you choose, it seems that HTMX serves its purpose well, in making everyday HTML UIs more powerful with a minimum of additional coding.
https://www.infoworld.com/article/3802689/dynamic-web-apps-with-htmx-python-and-django.html
Related News |
25 sources
Current Date
Feb, Thu 13 - 11:39 CET
|