Quickstart

django-slugify-processor lets you run small text processors before Django’s slugify() finishes a slug. If you do not configure SLUGIFY_PROCESSORS, slugify() behaves like Django’s function, so you can swap imports first and add processors only when a term needs special handling.

Installation

Add django-slugify-processor to the Python environment that runs your Django project.

With pip:

$ python -m pip install django-slugify-processor

With uv:

$ uv add django-slugify-processor

Upgrade an existing environment with pip:

$ python -m pip install --upgrade django-slugify-processor

Upgrade an existing uv dependency:

$ uv add \
    --upgrade-package django-slugify-processor \
    django-slugify-processor

Usage

A processor is a function that takes a string and returns a string. Each function in SLUGIFY_PROCESSORS runs in order, then Django’s slugify() turns the final value into a slug.

Start with the term you need to preserve. This processor makes C++ become Cpp before Django strips punctuation:

>>> def slugify_programming_languages(value: str) -> str:
...     return value.replace("C++", "Cpp").replace("C#", "CSharp")
>>> slugify_programming_languages("C++ Programming")
'Cpp Programming'

Add the processor’s import string to your Django settings. Django resolves the string with django.utils.module_loading.import_string().

SLUGIFY_PROCESSORS = [
    "myapp.slugify_processors.slugify_programming_languages",
]

Use slugify() anywhere you would use Django’s function. This tested example uses the repository’s test_app processor; in an application, point SLUGIFY_PROCESSORS at your own module.

>>> from django.test import override_settings
>>> from django_slugify_processor.text import slugify
>>> with override_settings(
...     SLUGIFY_PROCESSORS=["test_app.coding.slugify_programming_languages"],
... ):
...     slugify("C++ Programming")
'cpp-programming'

Processors should stay pure and fast. The list is read for each slugification call, each import string is resolved with Django’s import helper, and each processor receives the previous processor’s output.

Templates

For templates, load the template filter when you want this pipeline in one template:

>>> from django.template import Context, Template
>>> from django.test import override_settings
>>> with override_settings(
...     INSTALLED_APPS=[
...         "django.contrib.contenttypes",
...         "django.contrib.auth",
...         "test_app",
...         "django_slugify_processor",
...     ],
...     TEMPLATES=[
...         {
...             "BACKEND": "django.template.backends.django.DjangoTemplates",
...             "APP_DIRS": True,
...         },
...     ],
...     SLUGIFY_PROCESSORS=["test_app.coding.slugify_programming_languages"],
... ):
...     Template(
...         '{% load slugify_processor %}{{ "C++ Programming"|slugify }}',
...     ).render(Context({}))
'cpp-programming'

For the rarer cases where every template should use this filter, install django_slugify_processor.templatetags.slugify_processor as a template builtin. That shadows Django’s slugify filter across the configured template engine, so reserve it for projects that want the same slug rules everywhere.

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "OPTIONS": {
            "builtins": [
                "django_slugify_processor.templatetags.slugify_processor",
            ],
        },
    },
]

Model Fields

For model fields, pass slugify() to a field option such as django-extensions’ AutoSlugField slugify_function or django-autoslug’s AutoSlugField slugify argument.

from django.db import models
from django_extensions.db.fields import AutoSlugField
from django_slugify_processor.text import slugify


class Article(models.Model):
    title = models.CharField(max_length=255)
    slug = AutoSlugField(populate_from="title", slugify_function=slugify)

Advanced: Developmental Releases

New versions of django-slugify-processor are published to PyPI as alpha, beta, or release candidates. In their versions you will see labels like a1, b1, and rc1; 1.10.0b4 means the fourth beta release of 1.10.0 before general availability.

Install the latest prerelease with pip:

$ python -m pip install --upgrade --pre django-slugify-processor

Or allow prereleases in a uv project dependency:

$ uv add \
    --prerelease allow \
    django-slugify-processor

Use trunk only when you need unreleased changes; it can break without notice.

With pip:

$ python -m pip install \
    --upgrade \
    'django-slugify-processor @ git+https://github.com/tony/django-slugify-processor.git'

With uv:

$ uv add \
    'django-slugify-processor @ git+https://github.com/tony/django-slugify-processor.git'