fix: admin 500 after login (jazzmin static manifest bug)

- add app.storage.ManifestStaticFilesStorage tolerating directory static
  refs (jazzmin renders {% static 'vendor/bootswatch' %}), still strict
  for genuinely missing files
- point STORAGES staticfiles backend at it
- guard empty EMAIL_PORT/EMAIL_USE_TLS env values in production settings
- route admin under /backend/, use sqlite in production, add create_admin
- add pillow and django-tinymce deps
This commit is contained in:
sankalp committed 2026-10-13 19:34:19 +05:45
1 parent 0bf927d93b
commit fbd4662bf8
9 files changed
+107 -25

No files matched your search

@@ -0,0 +1,29 @@
from django.contrib.auth import get_user_model
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = "Create a superuser with pre-defined credentials"
def handle(self, *args, **options):
User = get_user_model()
username = "udhamsilnepal@admin"
password = "this_is_pass@udhamsilnepal"
email = "info@udhamsilnepal.com.np"
if not User.objects.filter(username=username).exists():
User.objects.create_superuser(
username=username, email=email, password=password
)
self.stdout.write(
self.style.SUCCESS(f"Successfully created superuser: {username}")
)
else:
user = User.objects.get(username=username)
user.set_password(password)
user.is_superuser = True
user.is_staff = True
user.save()
self.stdout.write(
self.style.SUCCESS(f"Updated existing superuser: {username}")
)
+1 -1
View File
@@ -115,7 +115,7 @@ STORAGES = {
"BACKEND": "django.core.files.storage.FileSystemStorage",
},
"staticfiles": {
"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",
"BACKEND": "app.storage.ManifestStaticFilesStorage",
},
}
+45 -21
View File
@@ -3,52 +3,76 @@
from .base import * # noqa: F401, F403
DEBUG = False
SECRET_KEY = env('SECRET_KEY')
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=[])
SECRET_KEY = env("SECRET_KEY")
ALLOWED_HOSTS = env.list("ALLOWED_HOSTS", default=[])
# Database
# Using individual database parameters
# DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.mysql',
# 'PORT': env('DB_PORT', default='3306'),
# 'NAME': env('DB_NAME'),
# 'USER': env('DB_USER'),
# 'PASSWORD': env('DB_PASSWORD'),
# 'HOST': env('DB_HOST'),
# }
# }
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'PORT': env('DB_PORT', default='3306'),
'NAME': env('DB_NAME'),
'USER': env('DB_USER'),
'PASSWORD': env('DB_PASSWORD'),
'HOST': env('DB_HOST'),
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
"OPTIONS": {
"transaction_mode": "IMMEDIATE",
"timeout": 5, # seconds
"init_command": """
PRAGMA journal_mode=WAL;
PRAGMA synchronous=NORMAL;
PRAGMA mmap_size = 134217728;
PRAGMA journal_size_limit = 27103364;
PRAGMA cache_size=2000;
""",
},
}
}
# CORS settings for production
# Filter out empty strings from FRONTEND_URL
CORS_ALLOWED_ORIGINS = env.list('FRONTEND_URL', default=[])
CORS_ALLOWED_ORIGINS = env.list("FRONTEND_URL", default=[])
CORS_ALLOW_CREDENTIALS = True
# Additional CORS security for production
CORS_ALLOW_PRIVATE_NETWORK = False
# Email settings
# Empty environment values (e.g. `EMAIL_PORT=` in .env) must fall back to the
# defaults instead of crashing `env.int`/`env.bool` at settings import time.
email_host = env("EMAIL_HOST", default="") or "smtp.gmail.com"
email_port = int(env("EMAIL_PORT", default="") or 587)
email_use_tls = env.bool("EMAIL_USE_TLS") if env("EMAIL_USE_TLS", default="") else True
MAILERS = {
'default': {
'BACKEND': 'django.core.mail.backends.smtp.EmailBackend',
'OPTIONS': {
'host': env('EMAIL_HOST', default='smtp.gmail.com'),
'port': env.int('EMAIL_PORT', default=587),
'use_tls': env.bool('EMAIL_USE_TLS', default=True),
'username': env('EMAIL_HOST_USER', default=''),
'password': env('EMAIL_HOST_PASSWORD', default=''),
"default": {
"BACKEND": "django.core.mail.backends.smtp.EmailBackend",
"OPTIONS": {
"host": email_host,
"port": email_port,
"use_tls": email_use_tls,
"username": env("EMAIL_HOST_USER", default=""),
"password": env("EMAIL_HOST_PASSWORD", default=""),
},
},
}
DEFAULT_FROM_EMAIL = env('EMAIL_HOST_USER', default='')
SERVER_EMAIL = env('EMAIL_HOST_USER', default='')
DEFAULT_FROM_EMAIL = env("EMAIL_HOST_USER", default="")
SERVER_EMAIL = env("EMAIL_HOST_USER", default="")
# Security settings for production
SECURE_SSL_REDIRECT = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
# Session settings
SESSION_COOKIE_SECURE = True
+22
View File
@@ -0,0 +1,22 @@
import os
from whitenoise.storage import CompressedManifestStaticFilesStorage
class ManifestStaticFilesStorage(CompressedManifestStaticFilesStorage):
"""WhiteNoise manifest storage that tolerates references to static directories.
django-jazzmin renders ``{% static 'vendor/bootswatch' %}`` (a directory) for
its client-side theme base path. Directories have no manifest entry, so the
stock ``ManifestStaticFilesStorage`` raises ``ValueError`` and every admin
page 500s after login. Genuinely missing *files* still raise as usual.
"""
def stored_name(self, name):
try:
return super().stored_name(name)
except ValueError:
_, extension = os.path.splitext(name)
if not extension:
return name
raise
+7 -2
View File
@@ -4,10 +4,11 @@ from django.conf import settings
from django.contrib import admin
from django.urls import include, path, re_path
from django.views.static import serve
from app.views import index
urlpatterns = [
path("admin/", admin.site.urls),
path("backend/", admin.site.urls),
path("tinymce/", include("tinymce.urls")),
path("api/", include("app.api.urls")),
]
@@ -18,5 +19,9 @@ urlpatterns += [
serve,
{"document_root": settings.MEDIA_ROOT},
),
re_path(r"^(?!(?:api|admin|tinymce|media|static)(?:/|$)).*$", index, name="index"),
re_path(
r"^(?!(?:api|backend|admin|tinymce|media|static)(?:/|$)).*$",
index,
name="index",
),
]
Binary file not shown.
View File
Whitespace-only changes.
+2
View File
@@ -8,3 +8,5 @@ mysqlclient>=2.2.8
django-vite>=3.1.0
gunicorn>=26.2.0
django-filter>=26.1
pillow>=12.3.0
django-tinymce>=5.0.0
+1 -1
View File
@@ -1 +1 @@
VITE_API_BASE_URL=http://localhost:8000/api
VITE_API_BASE_URL=https://udhamsilnepal.com.np/api