django-taggit
django-taggit is a reusable Django application for simple, yet powerful, tagging. It provides a `TaggableManager` to easily add tags to any Django model. The current version is 6.1.0, and it maintains an active development and release cadence, supporting modern Django and Python versions.
Warnings
- breaking As of `django-taggit` 6.1.0, Python 3.8 is no longer supported; Python 3.9+ is now required. While PyPI metadata may still show `>=3.8`, the official documentation and changelog confirm the updated requirement.
- breaking In `django-taggit` 6.0.0, the default ordering of tag items on instances changed to be by primary key (effectively creation date). Previously, tag items were not explicitly ordered, which could lead to inconsistent results.
- gotcha Tag lookups are case-sensitive by default. Tags like 'Python' and 'python' will be treated as distinct tags.
- gotcha When using `django-taggit` with Django REST Framework, the `TaggableManager` field does not behave like a simple list for serialization. Direct `ModelSerializer` usage for tags might lead to exceptions.
- breaking In `django-taggit` 5.0.0, there was an issue where package metadata incorrectly stated `Django >=3.2`. This could lead to `pip` automatically upgrading Django to an incompatible version (e.g., Django 4.0 for a Django 2.2 project) upon `django-taggit` installation if version bounds were not specified.
- gotcha If you wish to use custom Tag or Through models, you must remove `'taggit'` from your `INSTALLED_APPS` setting. Including it will create `django-taggit`'s default models, which might conflict or be redundant.
Install
-
pip install django-taggit
Imports
- TaggableManager
from taggit.managers import TaggableManager
- Tag
from taggit.models import Tag
Quickstart
import os
import django
from django.conf import settings
from django.db import models
settings.configure(
INSTALLED_APPS=[
'django.contrib.auth',
'django.contrib.contenttypes',
'taggit',
],
DATABASES={
'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:'}
},
SECRET_KEY=os.environ.get('DJANGO_SECRET_KEY', 'a-very-secret-key-that-should-be-changed'),
DEFAULT_AUTO_FIELD='django.db.models.BigAutoField',
)
django.setup()
from taggit.managers import TaggableManager
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
tags = TaggableManager()
def __str__(self):
return self.title
# --- Example Usage ---
# After migrations (run `python manage.py migrate` in a real project):
# from django.core.management import call_command
# call_command('migrate', interactive=False)
# Create a post
post1 = Post.objects.create(title='My First Post', content='Content goes here.')
post1.tags.add('python', 'django', 'tutorial')
post2 = Post.objects.create(title='Another Post', content='More content.')
post2.tags.add('python', 'web-dev')
print(f"Post 1 tags: {list(post1.tags.names())}")
print(f"Posts tagged with 'python': {Post.objects.filter(tags__name__in=['python']).count()}")
print(f"All tags: {list(TaggableManager().all_tags().names())}")
# Remove a tag
post1.tags.remove('tutorial')
print(f"Post 1 tags after removal: {list(post1.tags.names())}")