A modern Django Admin extension with enhanced UI/UX, dashboard, feedback, file management, rate limiting, IP blacklisting, and advanced admin integrations built on django-unfold.
Project description
django-whiteneuron
A modern Django Admin extension focused on UI/UX, dashboard, feedback, file management, and advanced admin integrations — built on top of django-unfold.
Current Version
- 0.3.1.1
Compatibility
- Python >= 3.11
- Django >= 5.2.13
- django-unfold >= 0.85.0
- Tailwind CSS 4.x + daisyUI 5.x (for the bundled frontend styles)
Changelog
See CHANGELOG.md for the full version history.
Latest: v0.3.1.1 (2026-04-16)
Fix: permission_viewer_callback missing unauthenticated guard; add md2html-tailwind4 dependency
- Fixed:
base/utils.py—permission_viewer_callbacknow checksrequest.user.is_authenticatedbefore returningTrue, preventing unauthenticated (anonymous) users from passing the permission check. - Fixed:
base/settings.py— UNFOLD navigation Feedbacks menu item permission callback changed frompermission_non_guest_callbacktopermission_viewer_callbackfor consistency. - Added:
pyproject.toml— addedmd2html-tailwind4>=1.0.0as a dependency.
Installation
From PyPI (recommended)
pip install django-whiteneuron
Or with uv:
uv add django-whiteneuron
Specific version from PyPI
uv add "django-whiteneuron==0.2.37"
From GitHub tag
uv add "git+https://github.com/White-Neuron/django-whiteneuron.git@v0.2.37"
From local source
uv pip install -e .
Django Configuration
Add the apps at the top of INSTALLED_APPS:
INSTALLED_APPS = [
"whiteneuron",
"whiteneuron.base",
"whiteneuron.feedbacks",
"whiteneuron.file_management",
"whiteneuron.contrib",
"whiteneuron.dashboard",
# ... your other apps
]
Add the required middleware (order matters):
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"whiteneuron.base.middleware.RateLimitMiddleware", # ← immediately after SecurityMiddleware
"whitenoise.middleware.WhiteNoiseMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"whiteneuron.base.middleware.ReadonlyExceptionHandlerMiddleware",
"whiteneuron.base.middleware.UserActivityMiddleware", # ← after AuthenticationMiddleware
"whiteneuron.base.middleware.ThreadLocalMiddleware",
]
Set the custom user model:
AUTH_USER_MODEL = "base.User"
UNFOLD Configuration Example
from django.templatetags.static import static
from django.utils.translation import gettext_lazy as _
UNFOLD = {
"SITE_HEADER": _("White Neuron"),
"SITE_TITLE": _("White Neuron Admin"),
"SITE_SUBHEADER": _("Admin panel"),
# Use SITE_ICON instead of SITE_LOGO to keep SITE_TITLE rendering correctly
"SITE_ICON": {
"light": lambda request: static("base/images/logo/WhiteNeuron.png"),
"dark": lambda request: static("base/images/logo/WhiteNeuron.png"),
},
"SITE_FAVICONS": [
{
"rel": "icon",
"sizes": "32x32",
"type": "image/svg+xml",
"href": lambda request: static("base/images/logo/WhiteNeuron.png"),
},
],
"SHOW_HISTORY": False,
"SHOW_LANGUAGES": True,
"SHOW_VIEW_ON_SITE": True,
"SHOW_BACK_BUTTON": True,
"DASHBOARD_CALLBACK": "whiteneuron.dashboard.views.dashboard_callback",
"LOGIN": {
"image": lambda request: static("base/images/login-bg.jpg"),
},
"STYLES": [
lambda request: static("base/css/styles.css"),
lambda request: static("base/css/btn-styles.css"),
lambda request: static("base/css/loading.css"),
],
"SCRIPTS": [
lambda request: static("base/js/loading.js"),
lambda request: static("base/js/whiteneuron.js"),
],
"BORDER_RADIUS": "6px",
}
Frontend (Tailwind 4 + daisyUI 5)
Install frontend dependencies:
npm install -D @tailwindcss/cli@next daisyui@latest
Build CSS using the provided script:
bash scripts/tailwind.sh
Or run directly:
npx @tailwindcss/cli -i styles.css -o whiteneuron/static/base/css/styles.css --minify
Running the Local Example
cd whiteneuron
python manage.py migrate
python manage.py runserver
Access the admin at: http://127.0.0.1:8000/admin/
Building the Package
uv build
Or use the all-in-one build script:
bash scripts/build.sh
Rate Limiting
RateLimitMiddleware limits by IP; UserActivityMiddleware limits by authenticated user. Redis is required for accuracy in multi-worker environments.
# settings.py (hoặc env)
RATE_LIMIT_REQUESTS = 60 # số request tối đa / window (theo IP)
RATE_LIMIT_WINDOW = 60 # tính bằng giây
USER_RATE_LIMIT_REQUESTS = 60 # theo user đã đăng nhập
USER_RATE_LIMIT_WINDOW = 60
Corresponding env vars: RATE_LIMIT_REQUESTS, RATE_LIMIT_WINDOW, USER_RATE_LIMIT_REQUESTS, USER_RATE_LIMIT_WINDOW.
When the limit is exceeded:
- API requests (
/api/orAccept: application/json) → JSON{"detail": "Too many requests."}with status 429. - Browser requests → renders
429.htmltemplate withRetry-Afterheader.
IP Blacklist
Two protection layers operate in parallel. Both are checked before rate limiting and return 403 immediately.
Static — .env (CIDR ranges, infrastructure bans)
Loaded at startup, supports IPv4/IPv6 and CIDR:
# .env
IP_BLACKLIST=185.220.101.5,194.165.16.0/22,2001:db8::/32
Requires a Daphne/Gunicorn restart to apply new entries.
Dynamic — Django Admin + Redis (real-time)
Managed via System → IP Blacklist in the admin panel (superuser only):
- Permanent block: leave
blocked_untilempty - Temporary block: set
blocked_until→ Redis TTL auto-expires, no cron needed - Quick block from logs: User Activity → select records → Block IP address action → Redis key set immediately, no restart needed
Request → check static env blacklist (O(1))
→ check cache.get('blacklist:dynamic:<ip>') (1 Redis GET)
→ 403 nếu match, không tốn rate limit check
Error Pages
Error templates live in whiteneuron/templates/ and are used automatically by Django when DEBUG=False:
| Template | Error | Notes |
|---|---|---|
400.html |
Bad Request | |
403.html |
Forbidden | |
404.html |
Not Found | |
429.html |
Too Many Requests | Rendered manually by middleware, passes {{ retry_after }} |
500.html |
Server Error |
No need to register handler400/403/404/500 — Django resolves templates automatically via APP_DIRS=True.
Environment Configuration
Copy env.example to your environment file and update variables such as DATABASE, REDIS, EMAIL, and ALLOWED_HOSTS.
Contact
- Email: anhnt@whiteneuron.com
- Website: https://whiteneuron.ai
- GitHub: https://github.com/White-Neuron/django-whiteneuron
License
MIT License.
Project details
Release history Release notifications | RSS feed
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_whiteneuron-0.3.1.1.tar.gz.
File metadata
- Download URL: django_whiteneuron-0.3.1.1.tar.gz
- Upload date:
- Size: 1.4 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
238da24ea0c60d57ae92133d2e606d5aebcc96dde95538672895e075abe0b184
|
|
| MD5 |
f1f479bf0cdf4a34a914ccf11e36d43e
|
|
| BLAKE2b-256 |
8c241cdfa479965f726f6b3cc47412d8864ae31a7986d50a701ae52f26dc93e8
|
Provenance
The following attestation bundles were made for django_whiteneuron-0.3.1.1.tar.gz:
Publisher:
python-publish.yml on White-Neuron/django-whiteneuron
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_whiteneuron-0.3.1.1.tar.gz -
Subject digest:
238da24ea0c60d57ae92133d2e606d5aebcc96dde95538672895e075abe0b184 - Sigstore transparency entry: 1315052153
- Sigstore integration time:
-
Permalink:
White-Neuron/django-whiteneuron@6ff2a5bf5a1c5472ff851ddedcc991023628ab3e -
Branch / Tag:
refs/tags/v0.3.1.1 - Owner: https://github.com/White-Neuron
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@6ff2a5bf5a1c5472ff851ddedcc991023628ab3e -
Trigger Event:
release
-
Statement type:
File details
Details for the file django_whiteneuron-0.3.1.1-py3-none-any.whl.
File metadata
- Download URL: django_whiteneuron-0.3.1.1-py3-none-any.whl
- Upload date:
- Size: 1.5 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1fb60966aec531090aad0d2c53295ccac346ba47e59f706d73034ddf271dd9de
|
|
| MD5 |
bd00308bba31ec701cfcfcee13d1967d
|
|
| BLAKE2b-256 |
24a3cae426e3ee9d2a8a106dcc61fd1c6af8c36b2c35802927e2d6ab3bbb9a8b
|
Provenance
The following attestation bundles were made for django_whiteneuron-0.3.1.1-py3-none-any.whl:
Publisher:
python-publish.yml on White-Neuron/django-whiteneuron
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_whiteneuron-0.3.1.1-py3-none-any.whl -
Subject digest:
1fb60966aec531090aad0d2c53295ccac346ba47e59f706d73034ddf271dd9de - Sigstore transparency entry: 1315052222
- Sigstore integration time:
-
Permalink:
White-Neuron/django-whiteneuron@6ff2a5bf5a1c5472ff851ddedcc991023628ab3e -
Branch / Tag:
refs/tags/v0.3.1.1 - Owner: https://github.com/White-Neuron
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@6ff2a5bf5a1c5472ff851ddedcc991023628ab3e -
Trigger Event:
release
-
Statement type: