Files
skelet/core/models.py
T

284 lines
7.6 KiB
Python
Raw Normal View History

2026-07-06 17:30:34 +08:00
from django.db import models
from django.core.exceptions import ValidationError
from django.core.validators import MinValueValidator, MaxValueValidator
from modelcluster.fields import ParentalManyToManyField
from wagtail.models import Page
from wagtail.admin.panels import FieldPanel, MultiFieldPanel
from wagtail.fields import RichTextField
from wagtail.snippets.models import register_snippet
2026-07-06 17:30:34 +08:00
class ScenarioIndexPage(Page):
parent_page_types = ["home.HomePage"]
subpage_types = ["core.ScenarioPage"]
max_count = 1
content_panels = Page.content_panels
class Meta:
verbose_name = "Scenario Index"
class ScenarioPage(Page):
parent_page_types = ["core.ScenarioIndexPage"]
subpage_types = []
content_panels = Page.content_panels
class Meta:
verbose_name = "Scenario"
@register_snippet
class Language(models.Model):
name = models.CharField(max_length=50, unique=True)
slug = models.SlugField(max_length=50, unique=True)
panels = [
FieldPanel("name"),
FieldPanel("slug"),
]
class Meta:
ordering = ["name"]
verbose_name = "Language"
verbose_name_plural = "Languages"
def __str__(self):
return self.name
@register_snippet
class Framework(models.Model):
name = models.CharField(max_length=50, unique=True)
slug = models.SlugField(max_length=50, unique=True)
panels = [
FieldPanel("name"),
FieldPanel("slug"),
]
class Meta:
ordering = ["name"]
verbose_name = "Framework"
verbose_name_plural = "Frameworks"
def __str__(self):
return self.name
@register_snippet
class DatabaseOption(models.Model):
name = models.CharField(max_length=50, unique=True)
slug = models.SlugField(max_length=50, unique=True)
panels = [
FieldPanel("name"),
FieldPanel("slug"),
]
class Meta:
ordering = ["name"]
verbose_name = "Database Option"
verbose_name_plural = "Database Options"
def __str__(self):
return self.name
@register_snippet
class SkeletonFeature(models.Model):
name = models.CharField(max_length=50, unique=True)
slug = models.SlugField(max_length=50, unique=True)
panels = [
FieldPanel("name"),
FieldPanel("slug"),
]
class Meta:
ordering = ["name"]
verbose_name = "Skeleton Feature"
verbose_name_plural = "Skeleton Features"
def __str__(self):
return self.name
class ProjectIndexPage(Page):
parent_page_types = ["home.HomePage"]
subpage_types = ["core.SkeletonProjectPage"]
max_count = 1
content_panels = Page.content_panels
class Meta:
verbose_name = "Project Index"
class SkeletonProjectPage(Page):
MATURITY_CHOICES = [
("experimental", "Experimental"),
("stable", "Stable"),
("mature", "Mature"),
]
MAINTENANCE_CHOICES = [
("active", "Active"),
("slow", "Slow"),
("unknown", "Unknown"),
("archived", "Archived"),
]
summary = models.TextField()
github_url = models.URLField()
official_url = models.URLField(blank=True)
license_name = models.CharField(max_length=100, blank=True)
scenarios = ParentalManyToManyField("core.ScenarioPage", blank=False)
languages = ParentalManyToManyField("core.Language", blank=False)
frameworks = ParentalManyToManyField("core.Framework", blank=True)
databases = ParentalManyToManyField("core.DatabaseOption", blank=True)
features = ParentalManyToManyField("core.SkeletonFeature", blank=True)
maturity = models.CharField(max_length=20, choices=MATURITY_CHOICES)
maintenance_status = models.CharField(
max_length=20, choices=MAINTENANCE_CHOICES, default="unknown"
)
structure_score = models.IntegerField(
validators=[MinValueValidator(0), MaxValueValidator(5)]
)
docs_score = models.IntegerField(
validators=[MinValueValidator(0), MaxValueValidator(5)]
)
tests_score = models.IntegerField(
validators=[MinValueValidator(0), MaxValueValidator(5)]
)
example_score = models.IntegerField(
validators=[MinValueValidator(0), MaxValueValidator(5)]
)
dependency_score = models.IntegerField(
validators=[MinValueValidator(0), MaxValueValidator(5)]
)
incremental_score = models.IntegerField(
validators=[MinValueValidator(0), MaxValueValidator(5)]
)
recommended_for = RichTextField()
not_recommended_for = RichTextField(blank=True)
review_notes = RichTextField(blank=True)
is_featured = models.BooleanField(default=False)
is_sponsored = models.BooleanField(default=False)
parent_page_types = ["core.ProjectIndexPage"]
subpage_types = []
@property
def total_score(self):
return (
self.structure_score
+ self.docs_score
+ self.tests_score
+ self.example_score
+ self.dependency_score
+ self.incremental_score
)
content_panels = Page.content_panels + [
MultiFieldPanel(
[
FieldPanel("summary"),
FieldPanel("github_url"),
FieldPanel("official_url"),
FieldPanel("license_name"),
],
heading="Basic Info",
),
MultiFieldPanel(
[
FieldPanel("scenarios"),
FieldPanel("languages"),
FieldPanel("frameworks"),
FieldPanel("databases"),
FieldPanel("features"),
FieldPanel("maturity"),
FieldPanel("maintenance_status"),
],
heading="Classification",
),
MultiFieldPanel(
[
FieldPanel("structure_score"),
FieldPanel("docs_score"),
FieldPanel("tests_score"),
FieldPanel("example_score"),
FieldPanel("dependency_score"),
FieldPanel("incremental_score"),
],
heading="Scores",
),
MultiFieldPanel(
[
FieldPanel("recommended_for"),
FieldPanel("not_recommended_for"),
FieldPanel("review_notes"),
],
heading="Review Content",
),
MultiFieldPanel(
[
FieldPanel("is_featured"),
FieldPanel("is_sponsored"),
],
heading="Display Options",
),
]
def clean(self):
super().clean()
if self.id is not None:
errors = {}
if not self.scenarios.exists():
errors["scenarios"] = ValidationError(
"At least one scenario is required."
)
if not self.languages.exists():
errors["languages"] = ValidationError(
"At least one language is required."
)
if errors:
raise ValidationError(errors)
class Meta:
verbose_name = "Skeleton Project"
class ArticleIndexPage(Page):
parent_page_types = ["home.HomePage"]
subpage_types = ["core.ArticlePage"]
max_count = 1
content_panels = Page.content_panels
class Meta:
verbose_name = "Article Index"
class ArticlePage(Page):
body = RichTextField()
related_projects = ParentalManyToManyField(
"core.SkeletonProjectPage", blank=True
)
parent_page_types = ["core.ArticleIndexPage"]
subpage_types = []
content_panels = Page.content_panels + [
FieldPanel("body"),
FieldPanel("related_projects"),
]
class Meta:
verbose_name = "Article"