Skip to content

Commit 481f3f4

Browse files
committed
feat: create Wagtail root page and default site on project run
Wagtail's admin home view requires a root Page and a default Site to build navigation URLs. When MIGRATION_MODULES points to empty directories Django uses syncdb, which skips RunPython data migrations and leaves these missing. This adds _setup_wagtail_initial_data to create them programmatically after migrations complete.
1 parent 693788a commit 481f3f4

1 file changed

Lines changed: 56 additions & 0 deletions

File tree

src/dbx_python_cli/commands/project.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,59 @@ def _enable_wagtail(project_path: Path, project_name: str) -> None:
813813
f.write(wagtail_block)
814814

815815

816+
def _setup_wagtail_initial_data(
817+
python_path: str,
818+
proj,
819+
env: dict,
820+
verbose: bool = False,
821+
) -> None:
822+
"""Create Wagtail root page and default site if Wagtail is enabled and they don't exist.
823+
824+
When MIGRATION_MODULES points to empty directories Django uses syncdb, which
825+
creates collections/tables but skips RunPython data migrations. Wagtail's
826+
0001 migration normally creates the root Page and a default Site; without
827+
them the admin home view cannot build the 'wagtailadmin_explore' URL.
828+
"""
829+
script_lines = [
830+
"import sys, django",
831+
"try:",
832+
" django.setup()",
833+
" from wagtail.models import Page",
834+
" if not Page.objects.filter(depth=1).exists():",
835+
" from django.conf import settings as _s",
836+
" from django.contrib.contenttypes.models import ContentType",
837+
" from wagtail.models import Locale, Site",
838+
" lang = (getattr(_s, 'LANGUAGE_CODE', 'en') or 'en').split('-')[0][:2]",
839+
" locale, _ = Locale.objects.get_or_create(language_code=lang)",
840+
" ct, _ = ContentType.objects.get_or_create(app_label='wagtailcore', model='page')",
841+
" root = Page.add_root(title='Root', slug='root', content_type=ct, locale=locale)",
842+
" print('wagtail_root_created')",
843+
" if not Site.objects.exists():",
844+
" Site.objects.create(hostname='localhost', root_page=root, is_default_site=True)",
845+
" print('wagtail_site_created')",
846+
"except ImportError:",
847+
" pass",
848+
"except Exception as e:",
849+
" print('wagtail_setup_error:' + str(e), file=sys.stderr)",
850+
]
851+
result = subprocess.run(
852+
[python_path, "-c", "\n".join(script_lines)],
853+
cwd=str(proj.project_path),
854+
env=env,
855+
capture_output=True,
856+
text=True,
857+
)
858+
stdout = result.stdout or ""
859+
stderr = result.stderr or ""
860+
if "wagtail_root_created" in stdout:
861+
typer.echo("✅ Created Wagtail root page")
862+
if "wagtail_site_created" in stdout:
863+
typer.echo("✅ Created Wagtail default site")
864+
if "wagtail_setup_error:" in stderr:
865+
msg = stderr.split("wagtail_setup_error:")[-1].strip()
866+
typer.echo(f"⚠️ Wagtail initial data setup failed: {msg}", err=True)
867+
868+
816869
def _add_frontend(
817870
project_name: str,
818871
directory: Path = Path("."),
@@ -1048,6 +1101,9 @@ def run_project(
10481101
raise typer.Exit(code=result.returncode)
10491102
typer.echo("✅ Migrations completed successfully")
10501103

1104+
# Create initial Wagtail data (root page + default site) if Wagtail is installed
1105+
_setup_wagtail_initial_data(python_path, proj, migrate_env, verbose)
1106+
10511107
# Create superuser (non-fatal if already exists)
10521108
su_email = os.getenv("PROJECT_EMAIL", "admin@example.com")
10531109
typer.echo("👑 Creating Django superuser 'admin'")

0 commit comments

Comments
 (0)