django-wee
A minimal Django application for creating and resolving short URLs, backed by Sqids codes and Django's cache framework.
Table of Contents
Requirements
- Python 3.10+
- Django 5.2+
Installation
pip install django-wee
Add django_wee to INSTALLED_APPS and include its URL patterns:
# settings.py
INSTALLED_APPS = [
...
"django_wee",
]
# urls.py
from django.urls import include, path
urlpatterns = [
...
path("s/", include("django_wee.urls")),
]
Then run the migrations:
python manage.py migrate
ASGI / async projects
If your project runs under an ASGI server, use the async URL module instead:
(path("s/", include("django_wee.urls_async")),)
Configuration
No mandatory configuration is required. See Settings reference for optional tunables.
Usage
Creating short URLs
Use the provided shortcut functions anywhere in your code:
from django.urls import reverse
from django_wee.shortcuts import create_short_url
short_url = create_short_url("https://example.com/a/very/long/url")
short_path = reverse("django_wee:redirect", args=[short_url.code])
# → "/s/aBcD1234/"
Pass an optional timezone-aware expiration datetime to create a URL that stops resolving after the specified time:
from datetime import timedelta
from django.urls import reverse
from django.utils import timezone
from django_wee.shortcuts import create_short_url
expiration = timezone.now() + timedelta(days=7)
short_url = create_short_url("https://example.com/a/very/long/url", expiration=expiration)
short_path = reverse("django_wee:redirect", args=[short_url.code])
If no expiration is provided, the short URL does not expire.
Alternatively, pass a ttl (time-to-live) to compute the expiration as a
offset from now. An int or float is interpreted as seconds, and a
timedelta is used directly. expiration and ttl are mutually exclusive:
from datetime import timedelta
from django.urls import reverse
from django_wee.shortcuts import create_short_url
short_url = create_short_url("https://example.com/a/very/long/url", ttl=timedelta(days=7))
short_path = reverse("django_wee:redirect", args=[short_url.code])
An async variant is also available:
from datetime import timedelta
from django.urls import reverse
from django.utils import timezone
from django_wee.shortcuts import acreate_short_url
expiration = timezone.now() + timedelta(days=7)
short_url = await acreate_short_url("https://example.com/a/very/long/url", expiration=expiration)
short_path = reverse("django_wee:redirect", args=[short_url.code])
Both functions validate the URL, persist a ShortUrl record, populate the cache, and return the persisted ShortUrl instance.
URLs without a scheme are normalized to https:// before validation and persistence. For example, create_short_url("example.com") stores https://example.com. Protocol-relative URLs (//example.com) receive an https: prefix, and URLs that already include a scheme are left unchanged.
Resolving short URLs
Requests to GET /s/<code>/ are handled automatically by the redirect view. The view checks the cache first and falls back to the database. Expired short URLs are not resolved. The response type (301 or 302) is controlled by the WEE_PERMANENT_REDIRECT setting.
Deleting expired URLs
The delete_expired_short_urls management command removes expired short URLs from the database:
python manage.py delete_expired_short_urls
By default, every short URL whose expires_at timestamp is in the past is deleted. Use --older-than to restrict the deletion to URLs that have been expired for at least the given duration:
python manage.py delete_expired_short_urls --older-than "7 days"
The duration accepts any format supported by Django's parse_duration (e.g. "7 days", "12 hours", "PT30M").
Use --dry-run to preview how many URLs would be deleted without performing the deletion:
python manage.py delete_expired_short_urls --older-than "7 days" --dry-run
Settings reference
| Setting | Default | Description |
|---|---|---|
WEE_CACHE_ALIAS |
"default" |
Cache alias (from CACHES) used to store short-URL mappings. |
WEE_CACHE_TIMEOUT |
3600 |
Cache TTL in seconds. |
WEE_CACHE_PREFIX |
"WEE" |
Prefix used for short-URL cache keys. Keys use the prefix:code format. |
WEE_MIN_LEN |
8 |
Minimum length of the generated Sqids code. |
WEE_ALPHABET |
Sqids default | Character set used to generate codes. |
WEE_PERMANENT_REDIRECT |
True |
If True, the redirect view returns HTTP 301; otherwise HTTP 302. |
License
django-wee is distributed under the terms of the MIT license.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_wee-0.2.2.tar.gz.
File metadata
- Download URL: django_wee-0.2.2.tar.gz
- Upload date:
- Size: 18.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aa0609238778ac6d46c6f1413522d6f38c8209d8d215d991a15320bc46310e93
|
|
| MD5 |
1b12f0946ad684999737e6255568f399
|
|
| BLAKE2b-256 |
e4dc86b410b46db36e04a1d8425ed66de79b03a3c660973c881a6e90b299963b
|
Provenance
The following attestation bundles were made for django_wee-0.2.2.tar.gz:
Publisher:
release.yml on hartungstenio/django-wee
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_wee-0.2.2.tar.gz -
Subject digest:
aa0609238778ac6d46c6f1413522d6f38c8209d8d215d991a15320bc46310e93 - Sigstore transparency entry: 2581896422
- Sigstore integration time:
-
Permalink:
hartungstenio/django-wee@56b92eeed280a777ccaaad2b31ab1cc4eba10788 -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/hartungstenio
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@56b92eeed280a777ccaaad2b31ab1cc4eba10788 -
Trigger Event:
release
-
Statement type:
File details
Details for the file django_wee-0.2.2-py3-none-any.whl.
File metadata
- Download URL: django_wee-0.2.2-py3-none-any.whl
- Upload date:
- Size: 17.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
965c3bf96fb49ca055488b90c40742f22988fd946364d91f8b12917d3f5e8777
|
|
| MD5 |
030b09cb5053d0815d3f5bb866bb44ac
|
|
| BLAKE2b-256 |
33998370d52f0fe8d06dbf039eea8cd5fed284c955e6a3aebd82c2e111b9bf89
|
Provenance
The following attestation bundles were made for django_wee-0.2.2-py3-none-any.whl:
Publisher:
release.yml on hartungstenio/django-wee
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_wee-0.2.2-py3-none-any.whl -
Subject digest:
965c3bf96fb49ca055488b90c40742f22988fd946364d91f8b12917d3f5e8777 - Sigstore transparency entry: 2581896431
- Sigstore integration time:
-
Permalink:
hartungstenio/django-wee@56b92eeed280a777ccaaad2b31ab1cc4eba10788 -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/hartungstenio
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@56b92eeed280a777ccaaad2b31ab1cc4eba10788 -
Trigger Event:
release
-
Statement type: