Building django-tomselect

Jack LinkeJack Linke
5 min read

Dynamic form selection widgets with autocomplete can transform how users interact with your application. They make navigating through long lists of options faster and more intuitive, and when paired with multi-column support, they provide the clarity needed to differentiate similar items quickly.

For years, I admired the power of django-autocomplete-light (DAL). It’s a feature-rich library that integrates seamlessly with Django. However, its extensive scope brings complexity, and development can feel slow at times. Many developers also gravitate toward Select2, but now that neither Django 5 nor Bootstrap 5 require jQuery, I’m hesitant to reintroduce such a dependency just for a form widget. With modern JavaScript options available, I wanted a solution that could offer:

  • A subset of DAL’s functionality—enough for most use cases, but simpler and easier to maintain.

  • Widgets like Select2 but without the jQuery dependency.

A Discovery

While scrolling through PyPI (a daily ritual for me - more consistent than my social media habits 😄), I stumbled upon mizdb-tomselect. It uses Tom Select, and the description of that library caught my attention:

"Tom Select is a dynamic, framework-agnostic, and lightweight (~16kb gzipped) <select> UI control. With autocomplete and native-feeling keyboard navigation, it’s useful for tagging, contact lists, country selectors, and so on."

That said, mizdb-tomselect was written for a specific use case: the MIZDB app. Its author openly acknowledges that: “It was written specifically with MIZDB in mind.” This limitation was understandable—many of my own packages were created to meet my specific needs, with the hope that they might help others too.

Why Tom Select? Why Not Something Else?

You might wonder why Tom Select stands out over other options. Here are my favorite features:

  • Lightweight and efficient: At just ~16kb gzipped, it adds minimal overhead.

  • Modern design: Autocomplete, keyboard navigation, columns, remote data, accessibility, plugins, and more are built-in.

  • Framework agnostic: It’s easy to integrate without requiring a specific JavaScript stack.

  • Styling: Comes with styling support for Bootstrap 4 & 5, or plain styling, with the easy possibility of supporting other css frameworks.

  • Plugins: Tom Select has several existing plugins, and development of new ones is very straightforward.

  • No jQuery dependency: This aligns well with Django 5 and Bootstrap 5’s modern approach.

Forking

By mid-2023, I realized that while mizdb-tomselect had significant potential, it was not quite as flexible as the ideal package I was dreaming of. I forked the package and began evolving it into django-tomselect, aiming to:

  • Remove app-specific constraints.

  • Make it adaptable for a variety of Django projects.

  • Provide a polished developer experience with more thorough documentation and examples.

However, my initial progress was hampered by time constraints, my less-than-optimal packaging workflow at the time, and gaps in my knowledge. Despite these hurdles, I continued using django-tomselect in my projects. Over time, its importance grew as I depended on it more heavily in business-critical applications.

A Breaking Point and a Breakthrough

By early 2024, I reached a breaking point. I needed django-tomselect to be more reliable and flexible, not just for my projects but for others who might rely on it. This realization coincided with two key changes:

  1. Improved Packaging Workflow: Over the past year, I’d refined my process for building and maintaining Python packages, making it easier to implement changes quickly.

  2. Prioritization: As django-tomselect became a more critical component in my business applications, I dedicated significant time in late 2024 to a major rewrite.

This rewrite touched every corner of the package. I added or updated:

  • Improved flexibility: More configuration options to suit diverse use cases.

  • Added hooks: It was important to me that the autocomplete QuerySet, the authorization, the templates, and the output data could all be overridden in a reasonable manner.

  • Comprehensive examples: From the original few example which showed how to do single & multiple selections with or without a tabular layout, the package now has 15 different examples from basic to advanced with ready-to-use snippets to help developers get started. The final two examples are nearly complete applications in their own right.

  • Better testing: Ensuring reliability across Django versions and various environments.

  • More thorough auth integration: It is important that end users are provided with relevant options that are applicable to the functionality they have been granted.

  • Media template tags: The django_tomselect template tag make it easier to include the Tom Select static content on base pages, especially when loading multiple forms or including forms with {% includes %} tags or via htmx. And you can specify the css framework to use and whether to use minified static, overriding the global settings if desired.

  • Clearer documentation: I rewrote and reorganized the docs so users could adopt the package with minimal friction.

The Road Ahead

With django-tomselect now much more robust, I’m excited to continue building on its foundation. There is still room to grow—perhaps adding integration with Django’s admin, enhancing performance for very large datasets, or providing advanced theming options (Tailwind?). Feedback from the community will be crucial as the package evolves.

In the meantime, I encourage you to give django-tomselect a try. If you’re looking for a clean, modern way to handle dynamic form selections, it might be just what you need. And as always, I’d love to hear about your experiences and suggestions for improvement.


PS: If you’re not already browsing PyPI daily, I highly recommend it. You’d be amazed at the gems waiting to be discovered!

0
Subscribe to my newsletter

Read articles from Jack Linke directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Jack Linke
Jack Linke

Jack Linke tends to learn the hard way - and shares the lessons from those experiences with others through blogging, tweets, and speaking engagements. He has been developing software and hardware projects off-and-on for most of his life, but much of his relevant web development experience has been hard-earned over the past four years during development of Watervize - a B2B2B SaaS web application to help irrigation water utility companies improve efficiency, analysis, and communication with staff and agriculture customers. Jack's technology interests include Python, the Django project, HTMX, GIS, graph theory, data storytelling, and visualization. He is a frequent contributor to the open source community and a contributing member of the Python Software Foundation. Outside of coding, Jack serves as a Marine Corps Officer, solves unusual math and logic problems, and makes a mess in the kitchen. Open Source Projects: django-postgresql-dag - Directed Acyclic Graphs with a variety of methods for both Nodes and Edges, and multiple exports django-calendardate - A Django calendar model with date metadata for querying against django-htmx-todo-list - An example of todo list application using Django and HTMX Mastodon (@jack@jacklinke.com)