from django.core.management.base import BaseCommand from wagtail.models import Page from home.models import HomePage from core.models import ( Language, Framework, DatabaseOption, ScenarioIndexPage, ScenarioPage, ProjectIndexPage, SkeletonProjectPage, ArticleIndexPage, ArticlePage, ) class Command(BaseCommand): help = "Seed database with user-confirmed initial content" def add_arguments(self, parser): parser.add_argument( "--clear", action="store_true", help="Delete existing content pages before seeding", ) def _clear_existing(self): for model in [ArticlePage, SkeletonProjectPage, ProjectIndexPage, ScenarioPage, ScenarioIndexPage, ArticleIndexPage]: model.objects.all().delete() self.stdout.write(" Cleared existing content pages") def _create_snippets(self): languages = [ ("Python", "python"), ("JavaScript", "javascript"), ("Go", "go"), ] for name, slug in languages: Language.objects.get_or_create(name=name, slug=slug) frameworks = [ ("Django", "django"), ("Flask", "flask"), ("Vue", "vue"), ("Wails", "wails"), ] for name, slug in frameworks: Framework.objects.get_or_create(name=name, slug=slug) databases = [ ("SQLite", "sqlite"), ("PostgreSQL", "postgresql"), ("MySQL", "mysql"), ] for name, slug in databases: DatabaseOption.objects.get_or_create(name=name, slug=slug) self.stdout.write(" Snippets created") def _create_pages(self): home = HomePage.objects.get(slug="home") if ScenarioIndexPage.objects.filter(slug="scenarios").exists(): scenario_index = ScenarioIndexPage.objects.get(slug="scenarios") project_index = ProjectIndexPage.objects.get(slug="projects") article_index = ArticleIndexPage.objects.get(slug="articles") self.stdout.write(" Page tree already exists, skipping") return scenario_index, project_index, article_index scenario_index = ScenarioIndexPage(title="Scenarios", slug="scenarios") home.add_child(instance=scenario_index) scenarios_data = [ ("Modern Desktop App Templates", "modern-desktop-app-templates"), ("CRM", "crm"), ("ERP", "erp"), ] for title, slug_val in scenarios_data: scenario = ScenarioPage(title=title, slug=slug_val) scenario_index.add_child(instance=scenario) project_index = ProjectIndexPage(title="Projects", slug="projects") home.add_child(instance=project_index) article_index = ArticleIndexPage(title="Articles", slug="articles") home.add_child(instance=article_index) self.stdout.write(" Page tree ready") return scenario_index, project_index, article_index def _get_snippets(self): lang_python = Language.objects.get(slug="python") lang_js = Language.objects.get(slug="javascript") lang_go = Language.objects.get(slug="go") fw_django = Framework.objects.get(slug="django") fw_flask = Framework.objects.get(slug="flask") fw_vue = Framework.objects.get(slug="vue") fw_wails = Framework.objects.get(slug="wails") db_sqlite = DatabaseOption.objects.get(slug="sqlite") db_pg = DatabaseOption.objects.get(slug="postgresql") db_mysql = DatabaseOption.objects.get(slug="mysql") return { "lang_python": lang_python, "lang_js": lang_js, "lang_go": lang_go, "fw_django": fw_django, "fw_flask": fw_flask, "fw_vue": fw_vue, "fw_wails": fw_wails, "db_sqlite": db_sqlite, "db_pg": db_pg, "db_mysql": db_mysql, } def _create_projects(self, project_index, s): crm_scenario = ScenarioPage.objects.get(slug="crm") erp_scenario = ScenarioPage.objects.get(slug="erp") desktop_scenario = ScenarioPage.objects.get(slug="modern-desktop-app-templates") projects = [ { "title": "DjangoCRM", "slug": "djangocrm", "summary": ( "A free open-source Python CRM built on Django Admin, " "integrating task management, email marketing, and data " "analytics. No proprietary frameworks, no vendor lock-in, " "no SaaS limitations." ), "github_url": "https://github.com/DjangoCRM/django-crm", "license_name": "Open Source", "scenarios": [crm_scenario], "languages": [s["lang_python"], s["lang_js"]], "frameworks": [s["fw_django"]], "databases": [s["db_sqlite"], s["db_pg"], s["db_mysql"]], "maturity": "stable", "maintenance_status": "active", "structure_score": 4, "docs_score": 4, "tests_score": 3, "example_score": 3, "dependency_score": 3, "incremental_score": 4, "recommended_for": ( "Feature-complete Django CRM that directly reuses Django " "Admin interface, focusing on business logic rather than " "reinventing UI frameworks." ), "is_featured": True, }, { "title": "django-erp-framework", "slug": "django-erp-framework", "summary": ( "A lightweight Django-based ERP development framework " "with built-in reporting engine, chart components, " "dashboard widget system, and custom admin backend." ), "github_url": "https://github.com/RamezIssac/django-erp-framework", "license_name": "Open Source", "scenarios": [erp_scenario], "languages": [s["lang_python"], s["lang_js"]], "frameworks": [s["fw_django"]], "databases": [s["db_sqlite"], s["db_pg"], s["db_mysql"]], "maturity": "stable", "maintenance_status": "active", "structure_score": 3, "docs_score": 3, "tests_score": 3, "example_score": 3, "dependency_score": 3, "incremental_score": 3, "recommended_for": ( "Lightweight and flexible Django ERP skeleton, suitable " "for rapid development of small to medium business systems." ), "is_featured": True, }, { "title": "EeazyCRM", "slug": "eeazycrm", "summary": ( "A lightweight open-source CRM built with Flask, " "covering customer, lead, and contact management " "with minimal code." ), "github_url": "https://github.com/jagjot2008/EeazyCRM", "license_name": "Open Source", "scenarios": [crm_scenario], "languages": [s["lang_python"]], "frameworks": [s["fw_flask"]], "databases": [s["db_sqlite"], s["db_mysql"]], "maturity": "experimental", "maintenance_status": "slow", "structure_score": 3, "docs_score": 2, "tests_score": 2, "example_score": 2, "dependency_score": 2, "incremental_score": 2, "recommended_for": ( "The most minimal Python CRM implementation, built with " "Flask microframework, ideal for learning and quick customization." ), }, { "title": "koalixcrm", "slug": "koalixcrm", "summary": ( "A Django-based open-source CRM + ERP system covering " "contacts, products, documents, projects, quotes, orders, " "invoices, purchasing, inventory, and accounting." ), "github_url": "https://github.com/KoalixSwitzerland/koalixcrm", "official_url": "http://www.koalix.org", "license_name": "Open Source", "scenarios": [crm_scenario, erp_scenario], "languages": [s["lang_python"]], "frameworks": [s["fw_django"]], "databases": [s["db_pg"], s["db_sqlite"]], "maturity": "stable", "maintenance_status": "active", "structure_score": 3, "docs_score": 4, "tests_score": 3, "example_score": 3, "dependency_score": 2, "incremental_score": 3, "recommended_for": ( "Feature-complete out-of-box lightweight Django ERP/CRM " "all-in-one solution." ), "is_featured": True, }, { "title": "SuiDemo", "slug": "suidemo", "summary": ( "A modern desktop application template built with Wails v3, " "featuring multilingual support, dark/light theme switching, " "SQLite CRUD, hotkey support, OCR, and extensible architecture." ), "github_url": "https://github.com/JinGongX/SuiDem", "license_name": "Open Source", "scenarios": [desktop_scenario], "languages": [s["lang_go"]], "frameworks": [s["fw_vue"], s["fw_wails"]], "databases": [s["db_sqlite"]], "maturity": "experimental", "maintenance_status": "active", "structure_score": 3, "docs_score": 3, "tests_score": 2, "example_score": 3, "dependency_score": 2, "incremental_score": 3, "recommended_for": ( "Quickly build cross-platform desktop applications " "with Go + Vue, suitable for rapid prototyping." ), }, ] for proj in projects: if SkeletonProjectPage.objects.filter(slug=proj["slug"]).exists(): self.stdout.write(f" Skipping existing project: {proj['title']}") continue scenarios = proj.pop("scenarios") languages = proj.pop("languages") frameworks = proj.pop("frameworks") databases = proj.pop("databases") project = SkeletonProjectPage(**proj) project_index.add_child(instance=project) project.languages.add(*languages) project.scenarios.add(*scenarios) if frameworks: project.frameworks.add(*frameworks) if databases: project.databases.add(*databases) project.save() self.stdout.write(f" Created project: {proj['title']}") def _create_articles(self, article_index): django_crm = SkeletonProjectPage.objects.get(slug="djangocrm") erp_framework = SkeletonProjectPage.objects.get(slug="django-erp-framework") articles = [ { "title": ( "DjangoCRM: A Free Open-Source Python CRM " "Built on Django Admin" ), "slug": "djangocrm-free-open-source-python-crm", "body": ( "

Project Positioning

" "

DjangoCRM is a free, open-source CRM built on Python " "and Django. It leverages the Django Admin interface rather " "than reinventing UI frameworks, allowing teams to focus on " "business logic, data integrity, and extensibility.

" "

Core Features

" "" "

Tech Stack

" "

Backend: Django + Python | Database: PostgreSQL / MySQL / SQLite

" ), "related_projects": [django_crm], }, { "title": ( "Why Choose django-erp-framework Instead of Odoo" ), "slug": "why-choose-django-erp-framework-over-odoo", "body": ( "

Comparison with Odoo

" "

Odoo's community edition is powerful but has a steep " "deployment and learning curve. django-erp-framework's design " "philosophy is 'just enough': it provides a core skeleton " "(reports + charts + widgets + admin) for you to build " "business logic on top, rather than hundreds of pre-built modules.

" "

Who Should Use It

" "" "

Key Characteristics

" "" ), "related_projects": [erp_framework], }, ] for art in articles: if ArticlePage.objects.filter(slug=art["slug"]).exists(): self.stdout.write(f" Skipping existing article: {art['title']}") continue related = art.pop("related_projects") article = ArticlePage(**art) article_index.add_child(instance=article) article.related_projects.add(*related) article.save() self.stdout.write(f" Created article: {art['title']}") def handle(self, *args, **options): if options["clear"]: self._clear_existing() if not options["clear"] and ScenarioIndexPage.objects.filter(slug="scenarios").exists(): self.stdout.write("Seed data already exists. Use --clear to reset.") return self.stdout.write("Creating snippets...") self._create_snippets() self.stdout.write("Creating page tree...") scenario_index, project_index, article_index = self._create_pages() self.stdout.write("Creating projects...") s = self._get_snippets() self._create_projects(project_index, s) self.stdout.write("Creating articles...") self._create_articles(article_index) # Verify self.stdout.write("") self.stdout.write("=== Seed verification ===") for proj in SkeletonProjectPage.objects.all(): sc = proj.scenarios.count() la = proj.languages.count() status = "OK" if sc >= 1 and la >= 1 else "MISSING_M2M" self.stdout.write( f" {proj.title}: scenarios={sc}, languages={la} [{status}]" ) for art in ArticlePage.objects.all(): rp = art.related_projects.count() status = "OK" if rp >= 1 else "MISSING_M2M" self.stdout.write( f" {art.title}: related_projects={rp} [{status}]" ) self.stdout.write( f"Scenarios: {ScenarioPage.objects.count()} " f"(≥3: {ScenarioPage.objects.count() >= 3})" ) self.stdout.write( f"Projects: {SkeletonProjectPage.objects.count()} " f"(≥5: {SkeletonProjectPage.objects.count() >= 5})" ) self.stdout.write( f"Articles: {ArticlePage.objects.count()} " f"(≥2: {ArticlePage.objects.count() >= 2})" ) self.stdout.write("=== Done ===")