Skip to main content

Django Tags Input

Ordered tags with autocomplete for Django forms and the admin. Use existing Django models for labels, optionally create new objects, and preserve the selection order through form saves and reloads.

PyPI version Python versions Django versions Monthly downloads BSD licence

CI on master Coverage on master Documentation build CodeQL on master Type checking: mypy, basedpyright and pyrefly Linting and formatting: Ruff Package manager: uv

Live demo | Documentation | PyPI | Source | Issues | Changelog

Django admin tags input with selected tags and autocomplete suggestions

The browser example runs real Django forms and SQLite on your device. It supports tag creation, existing choices and composite contact labels. Saved tags persist across reloads. No public Django server receives them.

Install

uv add django-tags-input

Python 3.10+ and Django 5.2+ are required. Django 6.x requires Python 3.12+. The package includes the widget's JavaScript and CSS, so using it does not require Node.js or a frontend build.

Add tags to the admin

In an existing Django app named blog, give posts a relation to tag objects:

from __future__ import annotations

from django.db import models


class Tag(models.Model):
    name: models.CharField[str, str] = models.CharField(max_length=100)

    def __str__(self) -> str:
        return self.name


class Post(models.Model):
    title: models.CharField[str, str] = models.CharField(max_length=200)
    tags: models.ManyToManyField[Tag, Tag] = models.ManyToManyField(
        Tag, blank=True,
    )

Each tag is an ordinary model row. The post stores the relationship through Django's automatically created join table.

Add the widget app and its mapping to your settings:

INSTALLED_APPS += ['tags_input']

TAGS_INPUT_MAPPINGS: dict[str, dict[str, object]] = {
    'blog.Tag': {'field': 'name', 'create_missing': True},
}

The key identifies the model. field supplies the visible label, and create_missing permits a new tag when no existing label matches. Keep it disabled when users must choose existing objects.

Include the autocomplete route in the project's urls.py:

from django.urls import include, path

urlpatterns += [
    path('tags-input/', include('tags_input.urls', namespace='tags_input')),
]

The namespace must be tags_input. One route serves the mapped models.

Register the post with the package's admin class:

from typing import ClassVar

from django.contrib import admin
from tags_input.admin import TagsInputAdmin

from .models import Post


@admin.register(Post)
class PostAdmin(TagsInputAdmin):
    tag_fields: ClassVar[list[str]] = ['tags']

Create the tables and open a post in the admin:

uv run python manage.py makemigrations blog
uv run python manage.py migrate
uv run python manage.py runserver

The tags field now offers autocomplete. Saving a new label creates a tag object after calling its clean() method. Existing labels become relations in the order entered.

Use a form outside the admin

Use both the field and the form mixin when the order must survive saves:

from __future__ import annotations

from typing import ClassVar

from django import forms
from tags_input.admin import TagsInputFormMixin
from tags_input.fields import TagsInputField

from .models import Post, Tag


class PostForm(TagsInputFormMixin, forms.ModelForm):
    tags: TagsInputField = TagsInputField(Tag.objects.all(), required=False)

    class Meta:
        model: type[Post] = Post
        fields: ClassVar[list[str]] = ['title', 'tags']

TagsInputField validates labels against its queryset. The mixin saves the related objects in that order. Render the form media alongside the form:

{{ form.media }}
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Save</button>
</form>

The media loads the bundled jQuery, jQuery UI and tagsinput plugin. If your page already loads compatible jQuery and jQuery UI, set TAGS_INPUT_INCLUDE_JQUERY = False.

A Django form with autocomplete and selected tags

Read the saved order with tags_input.utils.get_tags(post, 'tags'). post.tags.all() uses the model or database ordering instead.

Guides and development

  • Configuration: mappings, callbacks and matching rules.
  • Admin and inlines: choosing fields and handling relationship signals.
  • Order: how the join table records selections and where that approach applies.
  • Local examples: run the same forms and inspect the admin.
  • Contributing: uv, strict typing, linting, documentation and coverage checks.

The test matrix covers Python 3.10-3.14 with compatible Django 5.2, 6.0 and 6.1 releases. The project requires 100% statement and branch coverage and checks types with mypy, basedpyright and pyrefly.

Support

django-tags-input is maintained by Rick van Hattem in his own time.

If it saved you an afternoon, a tip covers an hour of issue triage: Ko-fi or GitHub Sponsors.

If your company funds its dependencies, this package is on thanks.dev.

ko-fi

Metadata

Release files for django-tags-input 7.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-tags-input 7.0.2
File Size Uploaded Provenance Actions
django_tags_input-7.0.2.tar.gz 1.1 MB With provenance Details for django_tags_input-7.0.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for django-tags-input 7.0.2
File Interpreter ABI Platform Actions
django_tags_input-7.0.2-py3-none-any.whl Python 3 none any Details for django_tags_input-7.0.2-py3-none-any.whl

Total release size: 1.3 MB

Release files / django_tags_input-7.0.2.tar.gz

Download URL django_tags_input-7.0.2.tar.gz
Size 1.1 MB
Tags Source
SHA-256 checksum
How to use checksums
60ce7571050ec84862ba332b74f5d2ef3873a56658ab648c21ba0314eca5bbc2
BLAKE2b-256 checksum
How to use checksums
5aaadbfe9ec6a5fc39c9d357753497ee7fd05b61b0422ff4e2b6e0b03b92ec36
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.

Transparency log

Release files / django_tags_input-7.0.2-py3-none-any.whl

Download URL django_tags_input-7.0.2-py3-none-any.whl
Size 169.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3393742be8e727a79a1dff8bf9e716f9635ae47ba5c4a97dd94860b55d324db0
BLAKE2b-256 checksum
How to use checksums
646b91a60069c17f15480917f207f99166d98ef954341baa7ed22efe81a628f3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.

Transparency log

Security for django-tags-input 7.0.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for django_tags_input-7.0.2.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 28, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

7.0.2 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page