# django-slugify-processor
Custom-[`slugify()`](https://docs.djangoproject.com/en/4.2/ref/utils/#django.utils.text.slugify)
support for django.
[![Python Package](https://img.shields.io/pypi/v/django-slugify-processor.svg)](https://pypi.org/project/django-slugify-processor/)
[![Build Status](https://github.com/tony/django-slugify-processor/workflows/tests/badge.svg)](https://django-slugify-processor.git-pull.com/)
[![Docs](https://github.com/tony/django-slugify-processor/workflows/docs/badge.svg)](https://github.com/tony/django-slugify-processor/actions?query=workflow%3Adocs)
[![Code Coverage](https://codecov.io/gh/tony/django-slugify-processor/branch/master/graph/badge.svg)](https://codecov.io/gh/tony/django-slugify-processor)
[![License](https://img.shields.io/github/license/tony/django-slugify-processor.svg)](https://github.com/tony/django-slugify-processor/blob/master/LICENSE)
# What are slugs?
_Slugs_ are URL's, typically generated from post titles, that you want to be both human readable and
a valid URL. They are SEO friendly.
Django provides a [`slugify()`](https://docs.djangoproject.com/en/4.2/ref/utils/#django.utils.text.slugify)
function which is also made available as a [default filter](https://github.com/django/django/blob/4.2.6/django/template/defaultfilters.py#L253-L261).
Django slugs can be automatically generated in django models via packages such as:
- [django-autoslug](https://pypi.python.org/pypi/django-autoslug)
([docs](https://pythonhosted.org/django-autoslug/),
[github](https://github.com/neithere/django-autoslug))
- [django-extensions](https://pypi.python.org/pypi/django-extensions) via
[AutoSlugField](https://django-extensions.readthedocs.io/en/latest/field_extensions.html)
([docs](https://django-extensions.readthedocs.io/en/latest/),
[github](https://github.com/django-extensions/django-extensions))
# The problem
This project is based on an article from [devel.tech](https://devel.tech) covering
[django's import strings](https://devel.tech/tips/n/djms3tTe/how-django-uses-deferred-imports-to-scale/).
Corner cases exist with slugification. For instance:
| Term | [`django.utils.text.slugify`] | What you want |
| ---- | ----------------------------- | ------------- |
| C | c (correct) | n/a |
| C++ | c | cpp |
| C# | c | c-sharp |
To make matters worse, if using a specialized model field like `AutoSlugField` from django-autoslug
or django-extensions, the default behavior may be to name the slugs for C++ and C# to "c-1", "c-2"
after "c" is taken.
Here's another case, acronyms / shorthands:
| Term | [`django.utils.text.slugify`] | What you (may) want |
| ------------------ | ----------------------------- | ------------------- |
| New York City | new-york-city | nyc |
| Y Combinator | y-combinator | yc |
| Portland | portland | pdx |
| Texas | texas | tx |
| $ | '' (empty) | usd, aud, etc? |
| US$ | us | usd |
| A$ | a | aud |
| bitcoin | bitcoin | btc |
| United States | united-states | usa |
| League of Legends | league-of-legends | league |
| AppleĀ® iPod Touch | apple-ipod-touch | ipod-touch |
Each website and niche has its own edge cases for slugs. So we need a solution that can scale, where
you can craft your own functions.
# How django-slugify-processor helps
This builds on top of [`django.utils.text.slugify`] to handle your django project's edgecases. By
default, django-slugify-processor will be a pass through to django's default behavior. Adding
slugification functions via your Django project's settings file allows you to adjust.
[`django.utils.text.slugify`]: https://github.com/django/django/blob/4.2.6/django/template/defaultfilters.py#L253-L261
# Installation
```console
$ pip install django-slugify-processor
```
# Configure
To create a processor, create a function that accepts a string, and returns a string. Assume this is
_project/app/slugify_processors.py_:
```python
def my_processor(value):
value = value.replace('++', 'pp')
return value
```
Inside of your settings, add a `SLUGIFY_PROCESSORS` list of strings that points to the function.
Anything that's compatible with
[import_string](https://docs.djangoproject.com/en/4.2/ref/utils/#django.utils.module_loading.import_string),
in your settings file:
```python
SLUGIFY_PROCESSORS = [
'project.app.slugify_processors.my_processor'
]
```
# Usage
## In normal django code
Import `slugify` from `django_slugify_processor.text`:
```python
from django_slugify_processor.text import slugify
print(slugify('C++'))
> 'cpp'
```
## Template code
django-slugify-processor is designed to override the built-in`slugify` filter.
### via load
You can load by default via `{% load django_slugify_processor %}` in your template.
In your settings `INSTALLED_APPS`:
```python
INSTALLED_APPS = [
'django_slugify_processor'
]
```
In your template:
```django
{% load slugify_processor %}
{{"C++"|slugify}}
```
### via built-in
To make this available in all templates, in the `OPTIONS` of your template engine, add
`django_slugify_processor.template_tags`:
```python
TEMPLATES = [{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'OPTIONS': {
'builtins': [
'django_slugify_processor.templatetags.slugify_processor',
],
},
}]
```
From within the template file:
```django
{{"C++"|slugify}}
```
Output should be: cpp
## Models
For the most up to date documentation, view the documentation for the plugin you're using (e.g.
django-autoslug or django-extensions).
To use django-slugify-processor's `slugify` instead of django's default, there will be a field
option to use the function.
### django-extensions
Tested with 1.9.7 (2017-11-26):
```python
from django.db import models
from django_extensions.db.fields import AutoSlugField
from django_slugify_processors.text import slugify
class MyModel(models.Model):
title = models.CharField(max_length=255)
slug = AutoSlugField(
populate_from='title',
slugify_function=slugify
)
```
### django-autoslug
Tested with 1.9.3 (2017-11-26):
```python
from django.db import models
from autoslug import AutoSlugField
from django_slugify_processors.text import slugify
class MyModel(models.Model):
title = models.CharField(max_length=255)
slug = AutoSlugField(
populate_from='title',
slugify=slugify
)
```
# Credits
- tox.ini based off DRF's (BSD 2-clause licensed)
- yapf configuration based off RTD / devel.tech's (MIT-licensed)
# Project details
- python support >= 3.8, pypy3
- django support > 3.2,
- Source https://github.com/tony/django-slugify-processor
- Docs https://django-slugify-processor.git-pull.com
- API https://django-slugify-processor.git-pull.com/api.html
- Changelog https://django-slugify-processor.git-pull.com/history.html
- Issues https://github.com/tony/django-slugify-processor/issues
- Test Coverage https://codecov.io/gh/tony/django-slugify-processor
- pypi https://pypi.python.org/pypi/django-slugify-processor
- Open Hub https://www.openhub.net/p/django-slugify-processor
- License MIT
- git repo
```bash
$ git clone https://github.com/tony/django-slugify-processor.git
```
## Development
Install stable:
```console
$ pip install django-slugify-processor
```
Local installation:
```console
$ git clone https://github.com/tony/django-slugify-processor.git
```
```console
$ cd ./django-slugify-processor
```
```console
$ poetry shell
```
```console
$ poetry install
```
Test:
```console
$ make test
```
Raw data
{
"_id": null,
"home_page": "https://django-slugify-processor.git-pull.com",
"name": "django-slugify-processor",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.8",
"maintainer_email": null,
"keywords": "django, slug, text",
"author": "Tony Narlock",
"author_email": "tony@git-pull.com",
"download_url": "https://files.pythonhosted.org/packages/fe/f6/c9d54539722c488b39516e703fbaf4d015c25606b40dd51fcb09a00e658d/django_slugify_processor-1.7.0.tar.gz",
"platform": null,
"description": "# django-slugify-processor\n\nCustom-[`slugify()`](https://docs.djangoproject.com/en/4.2/ref/utils/#django.utils.text.slugify)\nsupport for django.\n\n[![Python Package](https://img.shields.io/pypi/v/django-slugify-processor.svg)](https://pypi.org/project/django-slugify-processor/)\n[![Build Status](https://github.com/tony/django-slugify-processor/workflows/tests/badge.svg)](https://django-slugify-processor.git-pull.com/)\n[![Docs](https://github.com/tony/django-slugify-processor/workflows/docs/badge.svg)](https://github.com/tony/django-slugify-processor/actions?query=workflow%3Adocs)\n[![Code Coverage](https://codecov.io/gh/tony/django-slugify-processor/branch/master/graph/badge.svg)](https://codecov.io/gh/tony/django-slugify-processor)\n[![License](https://img.shields.io/github/license/tony/django-slugify-processor.svg)](https://github.com/tony/django-slugify-processor/blob/master/LICENSE)\n\n# What are slugs?\n\n_Slugs_ are URL's, typically generated from post titles, that you want to be both human readable and\na valid URL. They are SEO friendly.\n\nDjango provides a [`slugify()`](https://docs.djangoproject.com/en/4.2/ref/utils/#django.utils.text.slugify)\nfunction which is also made available as a [default filter](https://github.com/django/django/blob/4.2.6/django/template/defaultfilters.py#L253-L261).\n\nDjango slugs can be automatically generated in django models via packages such as:\n\n- [django-autoslug](https://pypi.python.org/pypi/django-autoslug)\n ([docs](https://pythonhosted.org/django-autoslug/),\n [github](https://github.com/neithere/django-autoslug))\n- [django-extensions](https://pypi.python.org/pypi/django-extensions) via\n [AutoSlugField](https://django-extensions.readthedocs.io/en/latest/field_extensions.html)\n ([docs](https://django-extensions.readthedocs.io/en/latest/),\n [github](https://github.com/django-extensions/django-extensions))\n\n# The problem\n\nThis project is based on an article from [devel.tech](https://devel.tech) covering\n[django's import strings](https://devel.tech/tips/n/djms3tTe/how-django-uses-deferred-imports-to-scale/).\n\nCorner cases exist with slugification. For instance:\n\n| Term | [`django.utils.text.slugify`] | What you want |\n| ---- | ----------------------------- | ------------- |\n| C | c (correct) | n/a |\n| C++ | c | cpp |\n| C# | c | c-sharp |\n\nTo make matters worse, if using a specialized model field like `AutoSlugField` from django-autoslug\nor django-extensions, the default behavior may be to name the slugs for C++ and C# to \"c-1\", \"c-2\"\nafter \"c\" is taken.\n\nHere's another case, acronyms / shorthands:\n\n| Term | [`django.utils.text.slugify`] | What you (may) want |\n| ------------------ | ----------------------------- | ------------------- |\n| New York City | new-york-city | nyc |\n| Y Combinator | y-combinator | yc |\n| Portland | portland | pdx |\n| Texas | texas | tx |\n| $ | '' (empty) | usd, aud, etc? |\n| US$ | us | usd |\n| A$ | a | aud |\n| bitcoin | bitcoin | btc |\n| United States | united-states | usa |\n| League of Legends | league-of-legends | league |\n| Apple\u00ae iPod Touch | apple-ipod-touch | ipod-touch |\n\nEach website and niche has its own edge cases for slugs. So we need a solution that can scale, where\nyou can craft your own functions.\n\n# How django-slugify-processor helps\n\nThis builds on top of [`django.utils.text.slugify`] to handle your django project's edgecases. By\ndefault, django-slugify-processor will be a pass through to django's default behavior. Adding\nslugification functions via your Django project's settings file allows you to adjust.\n\n[`django.utils.text.slugify`]: https://github.com/django/django/blob/4.2.6/django/template/defaultfilters.py#L253-L261\n\n# Installation\n\n```console\n$ pip install django-slugify-processor\n```\n\n# Configure\n\nTo create a processor, create a function that accepts a string, and returns a string. Assume this is\n_project/app/slugify_processors.py_:\n\n```python\ndef my_processor(value):\n value = value.replace('++', 'pp')\n return value\n```\n\nInside of your settings, add a `SLUGIFY_PROCESSORS` list of strings that points to the function.\nAnything that's compatible with\n[import_string](https://docs.djangoproject.com/en/4.2/ref/utils/#django.utils.module_loading.import_string),\nin your settings file:\n\n```python\nSLUGIFY_PROCESSORS = [\n 'project.app.slugify_processors.my_processor'\n]\n```\n\n# Usage\n\n## In normal django code\n\nImport `slugify` from `django_slugify_processor.text`:\n\n```python\nfrom django_slugify_processor.text import slugify\n\nprint(slugify('C++'))\n> 'cpp'\n```\n\n## Template code\n\ndjango-slugify-processor is designed to override the built-in`slugify` filter.\n\n### via load\n\nYou can load by default via `{% load django_slugify_processor %}` in your template.\n\nIn your settings `INSTALLED_APPS`:\n\n```python\nINSTALLED_APPS = [\n 'django_slugify_processor'\n]\n```\n\nIn your template:\n\n```django\n{% load slugify_processor %}\n{{\"C++\"|slugify}}\n```\n\n### via built-in\n\nTo make this available in all templates, in the `OPTIONS` of your template engine, add\n`django_slugify_processor.template_tags`:\n\n```python\nTEMPLATES = [{\n 'BACKEND': 'django.template.backends.django.DjangoTemplates',\n 'OPTIONS': {\n 'builtins': [\n 'django_slugify_processor.templatetags.slugify_processor',\n ],\n },\n}]\n```\n\nFrom within the template file:\n\n```django\n{{\"C++\"|slugify}}\n```\n\nOutput should be: cpp\n\n## Models\n\nFor the most up to date documentation, view the documentation for the plugin you're using (e.g.\ndjango-autoslug or django-extensions).\n\nTo use django-slugify-processor's `slugify` instead of django's default, there will be a field\noption to use the function.\n\n### django-extensions\n\nTested with 1.9.7 (2017-11-26):\n\n```python\nfrom django.db import models\n\nfrom django_extensions.db.fields import AutoSlugField\nfrom django_slugify_processors.text import slugify\n\nclass MyModel(models.Model):\n title = models.CharField(max_length=255)\n slug = AutoSlugField(\n populate_from='title',\n slugify_function=slugify\n )\n```\n\n### django-autoslug\n\nTested with 1.9.3 (2017-11-26):\n\n```python\nfrom django.db import models\n\nfrom autoslug import AutoSlugField\nfrom django_slugify_processors.text import slugify\n\nclass MyModel(models.Model):\n title = models.CharField(max_length=255)\n slug = AutoSlugField(\n populate_from='title',\n slugify=slugify\n )\n```\n\n# Credits\n\n- tox.ini based off DRF's (BSD 2-clause licensed)\n- yapf configuration based off RTD / devel.tech's (MIT-licensed)\n\n# Project details\n\n- python support >= 3.8, pypy3\n- django support > 3.2,\n- Source https://github.com/tony/django-slugify-processor\n- Docs https://django-slugify-processor.git-pull.com\n- API https://django-slugify-processor.git-pull.com/api.html\n- Changelog https://django-slugify-processor.git-pull.com/history.html\n- Issues https://github.com/tony/django-slugify-processor/issues\n- Test Coverage https://codecov.io/gh/tony/django-slugify-processor\n- pypi https://pypi.python.org/pypi/django-slugify-processor\n- Open Hub https://www.openhub.net/p/django-slugify-processor\n- License MIT\n- git repo\n\n ```bash\n $ git clone https://github.com/tony/django-slugify-processor.git\n ```\n\n## Development\n\nInstall stable:\n\n```console\n$ pip install django-slugify-processor\n```\n\nLocal installation:\n\n```console\n$ git clone https://github.com/tony/django-slugify-processor.git\n```\n\n```console\n$ cd ./django-slugify-processor\n```\n\n```console\n$ poetry shell\n```\n\n```console\n$ poetry install\n```\n\nTest:\n\n```console\n$ make test\n```\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "pipeline for slugification edgecases in django",
"version": "1.7.0",
"project_urls": {
"Bug Tracker": "https://github.com/tony/django-slugify-processor/issues",
"Changes": "https://github.com/tony/django-slugify-processor/blob/master/CHANGES",
"Documentation": "https://django-slugify-processor.git-pull.com",
"Homepage": "https://django-slugify-processor.git-pull.com",
"Repository": "https://github.com/tony/django-slugify-processor"
},
"split_keywords": [
"django",
" slug",
" text"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "8901e5e5aadf796906555445420f58ab3b4de04a47eb1ae0aeadb77b0447aee3",
"md5": "dda837cbac484a01012bfab0646a817a",
"sha256": "a8ac43fef1835eac735ef5f8f99379afe948c689d808bedb5af5e46d0df90ab6"
},
"downloads": -1,
"filename": "django_slugify_processor-1.7.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "dda837cbac484a01012bfab0646a817a",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.8",
"size": 7613,
"upload_time": "2024-08-17T20:44:56",
"upload_time_iso_8601": "2024-08-17T20:44:56.356606Z",
"url": "https://files.pythonhosted.org/packages/89/01/e5e5aadf796906555445420f58ab3b4de04a47eb1ae0aeadb77b0447aee3/django_slugify_processor-1.7.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "fef6c9d54539722c488b39516e703fbaf4d015c25606b40dd51fcb09a00e658d",
"md5": "801f88e5902596c2b40d79bd5966c4c0",
"sha256": "1446c13f5cdbea1cd6d85f5f72df09d6b954ecb119f1a02c69ad7e4979c48852"
},
"downloads": -1,
"filename": "django_slugify_processor-1.7.0.tar.gz",
"has_sig": false,
"md5_digest": "801f88e5902596c2b40d79bd5966c4c0",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.8",
"size": 10048,
"upload_time": "2024-08-17T20:44:57",
"upload_time_iso_8601": "2024-08-17T20:44:57.661996Z",
"url": "https://files.pythonhosted.org/packages/fe/f6/c9d54539722c488b39516e703fbaf4d015c25606b40dd51fcb09a00e658d/django_slugify_processor-1.7.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-08-17 20:44:57",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "tony",
"github_project": "django-slugify-processor",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "django-slugify-processor"
}