386 lines
16 KiB
Python
386 lines
16 KiB
Python
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": (
|
|
"<h2>Project Positioning</h2>"
|
|
"<p>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.</p>"
|
|
"<h2>Core Features</h2>"
|
|
"<ul><li>20+ interconnected CRM data models</li>"
|
|
"<li>Complex sales pipeline (Lead → Customer → Opportunity → Contract)</li>"
|
|
"<li>Task and project management with team assignment</li>"
|
|
"<li>Built-in email marketing and client</li>"
|
|
"<li>Analytical CRM with sales data analysis</li></ul>"
|
|
"<h2>Tech Stack</h2>"
|
|
"<p>Backend: Django + Python | Database: PostgreSQL / MySQL / SQLite</p>"
|
|
),
|
|
"related_projects": [django_crm],
|
|
},
|
|
{
|
|
"title": (
|
|
"Why Choose django-erp-framework Instead of Odoo"
|
|
),
|
|
"slug": "why-choose-django-erp-framework-over-odoo",
|
|
"body": (
|
|
"<h2>Comparison with Odoo</h2>"
|
|
"<p>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.</p>"
|
|
"<h2>Who Should Use It</h2>"
|
|
"<ul><li>Small teams needing internal management systems quickly</li>"
|
|
"<li>Python developers who don't want Odoo's complexity</li>"
|
|
"<li>Projects that need ERP functionality embedded in Django</li>"
|
|
"<li>Beginners learning ERP system architecture</li></ul>"
|
|
"<h2>Key Characteristics</h2>"
|
|
"<ul><li>Lightweight: only core infrastructure</li>"
|
|
"<li>Flexible: embeddable in existing Django projects</li>"
|
|
"<li>Clean: small codebase, easy to extend</li>"
|
|
"<li>Extensible: reporting engine usable standalone</li></ul>"
|
|
),
|
|
"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 ===")
|