feat(blog): add production taxonomy seed commands
Some checks failed
Backend CI/CD / test (push) Has been cancelled
Backend CI/CD / deploy (push) Has been cancelled

This commit is contained in:
2026-06-13 00:18:05 +03:30
parent 8b307196da
commit 0151497385
2 changed files with 236 additions and 0 deletions

View File

@@ -0,0 +1,125 @@
from __future__ import annotations
import sys
from django.core.management.base import BaseCommand
from apps.blog.models import Category
CATEGORIES = [
{
"name": "اخبار و اطلاعیه‌ها",
"description": "خبرها، اطلاعیه‌ها و گزارش‌های مرتبط با انجمن، دانشکده و جامعه دانشجویی.",
"children": [
("اخبار انجمن", "خبرها و گزارش‌های رسمی انجمن علمی مهندسی کامپیوتر."),
("اطلاعیه‌های آموزشی", "اطلاعیه‌های مهم آموزشی، انتخاب واحد، امتحانات و امور دانشجویی."),
("رویدادها و کارگاه‌ها", "معرفی، گزارش و پیگیری رویدادها، نشست‌ها و کارگاه‌ها."),
],
},
{
"name": "آموزش و مسیر یادگیری",
"description": "مطالب آموزشی و مسیرهای یادگیری برای دانشجویان علوم و مهندسی کامپیوتر.",
"children": [
("راهنمای شروع", "مطالب مقدماتی برای شروع برنامه‌نویسی، دانشگاه و مهارت‌آموزی."),
("آموزش‌های فنی", "آموزش‌های عملی، گام‌به‌گام و مسئله‌محور در حوزه‌های فنی."),
("منابع یادگیری", "معرفی کتاب، دوره، مستندات، مسیر مطالعه و منابع مفید."),
],
},
{
"name": "فناوری و مهندسی نرم‌افزار",
"description": "مقاله‌های فنی درباره توسعه نرم‌افزار، ابزارها، معماری و فناوری‌های روز.",
"children": [
("برنامه‌نویسی", "زبان‌ها، الگوها، نکته‌های کدنویسی و تجربه‌های عملی توسعه."),
("وب و اپلیکیشن", "فرانت‌اند، بک‌اند، موبایل، API و تجربه ساخت محصول."),
("دواپس و ابزارها", "لینوکس، گیت، CI/CD، استقرار، کانتینر و ابزارهای توسعه."),
],
},
{
"name": "هوش مصنوعی و داده",
"description": "مطالب مرتبط با هوش مصنوعی، یادگیری ماشین، داده و کاربردهای آن‌ها.",
"children": [
("یادگیری ماشین", "مفاهیم، تمرین‌ها و تجربه‌های یادگیری ماشین و مدل‌سازی."),
("علم داده", "تحلیل داده، مصورسازی، آمار کاربردی و پروژه‌های داده‌محور."),
("هوش مصنوعی کاربردی", "ابزارها، کاربردها، ایده‌ها و تجربه‌های عملی با AI."),
],
},
{
"name": "دانشگاه و پژوهش",
"description": "محتوای علمی، پژوهشی و دانشگاهی برای دانشجویان و اعضای انجمن.",
"children": [
("پژوهش دانشجویی", "تجربه‌ها، معرفی مقاله، ایده پژوهشی و همکاری‌های علمی."),
("درس و دانشگاه", "راهنمای درس‌ها، پروژه‌های درسی، امتحان و تجربه دانشگاهی."),
("مسابقات علمی", "برنامه‌نویسی رقابتی، مسابقات، چالش‌ها و آمادگی تیمی."),
],
},
{
"name": "پروژه‌ها و تجربه‌ها",
"description": "تجربه‌های واقعی دانشجویان از پروژه، کار تیمی، کارآموزی و مسیر حرفه‌ای.",
"children": [
("پروژه‌های دانشجویی", "معرفی، کالبدشکافی و گزارش پروژه‌های دانشجویی و تیمی."),
("کارآموزی و بازار کار", "رزومه، مصاحبه، کارآموزی، مسیر شغلی و تجربه ورود به کار."),
("تجربه‌های انجمنی", "روایت‌ها و درس‌آموخته‌های فعالیت در انجمن و تیم‌های دانشجویی."),
],
},
]
def console_safe(value: str) -> str:
encoding = sys.stdout.encoding or "utf-8"
return value.encode(encoding, errors="backslashreplace").decode(encoding)
class Command(BaseCommand):
help = "Create or update production blog categories for the CS association blog."
def add_arguments(self, parser):
parser.add_argument("--dry-run", action="store_true", help="Print planned categories without writing changes.")
def handle(self, *args, **options):
dry_run = options["dry_run"]
root_count = 0
child_count = 0
for root_spec in CATEGORIES:
if dry_run:
self.stdout.write(console_safe(f"[root] {root_spec['name']}"))
for child_name, _ in root_spec["children"]:
self.stdout.write(console_safe(f" [child] {child_name}"))
continue
root = self._upsert_category(
name=root_spec["name"],
description=root_spec["description"],
parent=None,
)
root_count += 1
for child_name, child_description in root_spec["children"]:
self._upsert_category(
name=child_name,
description=child_description,
parent=root,
)
child_count += 1
if dry_run:
self.stdout.write(self.style.WARNING("Dry run only. No categories were changed."))
return
self.stdout.write(self.style.SUCCESS(f"Blog categories synchronized: {root_count} roots, {child_count} children."))
def _upsert_category(self, *, name: str, description: str, parent: Category | None) -> Category:
if parent and parent.parent_id:
raise ValueError(f"Invalid category tree: parent '{parent.name}' is not a root category.")
category, _ = Category.all_objects.update_or_create(
name=name,
defaults={
"description": description,
"parent": parent,
"is_deleted": False,
"deleted_at": None,
},
)
return category

View File

@@ -0,0 +1,111 @@
from __future__ import annotations
import sys
from django.core.management.base import BaseCommand
from apps.blog.models import Tag
TAGS = [
"انجمن علمی",
"دانشکده",
"اطلاعیه",
"رویداد",
"کارگاه",
"گزارش رویداد",
"برنامه‌نویسی",
"پایتون",
"جاوااسکریپت",
"تایپ‌اسکریپت",
"جاوا",
"سی‌پلاس‌پلاس",
"گولنگ",
"فرانت‌اند",
"بک‌اند",
"React",
"Next.js",
"Django",
"REST API",
"پایگاه داده",
"PostgreSQL",
"Redis",
"گیت",
"لینوکس",
"Docker",
"DevOps",
"استقرار",
"امنیت",
"شبکه",
"سیستم‌عامل",
"الگوریتم",
"ساختمان داده",
"برنامه‌نویسی رقابتی",
"حل مسئله",
"هوش مصنوعی",
"یادگیری ماشین",
"یادگیری عمیق",
"علم داده",
"تحلیل داده",
"داده‌کاوی",
"پردازش زبان طبیعی",
"بینایی ماشین",
"پژوهش",
"مقاله‌خوانی",
"پروژه دانشجویی",
"پروژه درسی",
"تیم‌سازی",
"مدیریت پروژه",
"طراحی نرم‌افزار",
"معماری نرم‌افزار",
"تست نرم‌افزار",
"تجربه کاربری",
"طراحی رابط کاربری",
"اپن‌سورس",
"کارآموزی",
"رزومه",
"مصاحبه",
"مسیر شغلی",
"منابع یادگیری",
"کتاب",
"دوره آموزشی",
"تجربه دانشجویی",
"انتخاب واحد",
"امتحانات",
"آموزش",
"راهنمای شروع",
]
def console_safe(value: str) -> str:
encoding = sys.stdout.encoding or "utf-8"
return value.encode(encoding, errors="backslashreplace").decode(encoding)
class Command(BaseCommand):
help = "Create or update production blog tags for the CS association blog."
def add_arguments(self, parser):
parser.add_argument("--dry-run", action="store_true", help="Print planned tags without writing changes.")
def handle(self, *args, **options):
dry_run = options["dry_run"]
if dry_run:
for name in TAGS:
self.stdout.write(console_safe(f"[tag] {name}"))
self.stdout.write(self.style.WARNING("Dry run only. No tags were changed."))
return
count = 0
for name in TAGS:
Tag.all_objects.update_or_create(
name=name,
defaults={
"is_deleted": False,
"deleted_at": None,
},
)
count += 1
self.stdout.write(self.style.SUCCESS(f"Blog tags synchronized: {count} tags."))