from django.db import models class Memory(models.Model): """恋爱故事页,驱动前端尼泊尔本版式。""" class FeatureType(models.TextChoices): FIRST_MEET = "first_meet", "初见·抖音相识" FIRST_MEET_JU = "first_meet_ju", "初见·集电院" FIRST_MEET_RUI = "first_meet_rui", "初见·瑞幸咖啡" HEART_WINDOW = "heart_window", "心窗页" FISSURE_PAGE = "fissure_page", "裂缝对开页" STANDARD_NEPAL = "standard_nepal", "标准尼泊尔页" FIRST_MEET_TRAIN = "first_meet_train", "初见·高铁遇见" FIRST_MEET_TAIX = "first_meet_taix", "初见·出租牵手" FIRST_MEET_QUANJI = "first_meet_quanji", "初见·全季M爱" MAKE_LOVE = "make_love", "爱爱页" class NepalArtStyle(models.TextChoices): """每页可选不同尼泊尔视觉皮肤(备用可继续加枚举)。""" NONE = "none", "默认米黄" MANDALA_PINK = "mandala_pink", "粉曼陀罗" MANDALA_BLUE = "mandala_blue", "蓝曼陀罗" SPIRAL_ROSE = "spiral_rose", "玫瑰螺旋" SPIRAL_CYAN = "spiral_cyan", "青色螺旋" DAWN_MEET = "dawn_meet", "晨光·遇见" BLUSH_ARGUE = "blush_argue", "粉雾·争执" MINT_RECONCILE = "mint_reconcile", "薄荷·和好" SAFFRON_HOME = "saffron_home", "姜黄·小家" INDIGO_IKEA = "indigo_ikea", "靛蓝·漫游" LOTUS_PETAL = "lotus_petal", "莲花瓣" LOKTA_GOLD = "lokta_gold", "金边手工纸" OCEAN_PRAYER = "ocean_prayer", "海洋祈愿" DESERT_ROSE = "desert_rose", "沙漠玫瑰" NIGHT_STAR = "night_star", "夜空星屑" TERRA_TORN = "terra_torn", "赭石撕边" story_order = models.PositiveIntegerField( default=0, db_index=True, help_text="叙事顺序,数字越小越靠前。", ) date = models.DateField() event_title = models.CharField(max_length=200) main_text = models.TextField( blank=True, help_text="支持 Markdown。", ) unique_feature_type = models.CharField( max_length=32, choices=FeatureType.choices, default=FeatureType.STANDARD_NEPAL, ) nepal_art_style = models.CharField( max_length=48, choices=NepalArtStyle.choices, default=NepalArtStyle.NONE, blank=True, help_text="标准页背景/纹理;心窗与裂缝页也可作辅色参考。", ) image = models.ImageField(upload_to="memories/", blank=True, null=True) is_finale = models.BooleanField( default=False, help_text="终章:在解锁时间前仅可预览占位,到点后需手动打开。", ) class Meta: ordering = ["story_order", "id"] def __str__(self) -> str: return f"{self.story_order}. {self.event_title}" def save(self, *args, **kwargs): super().save(*args, **kwargs) if self.is_finale: Memory.objects.exclude(pk=self.pk).update(is_finale=False) class MemoryPhoto(models.Model): """同一回忆页可附加多张照片;与主图 `Memory.image` 一并展示,主图在前。""" memory = models.ForeignKey( Memory, on_delete=models.CASCADE, related_name="photos", help_text="所属故事页", ) image = models.ImageField(upload_to="memory_photos/") sort_order = models.PositiveSmallIntegerField( default=0, help_text="数字越小越靠前(排在主图之后)。", ) class Meta: ordering = ["sort_order", "id"] verbose_name = "附加照片" verbose_name_plural = "附加照片" def __str__(self) -> str: return f"{self.memory_id}·{self.sort_order}" class Guestbook(models.Model): nickname = models.CharField(max_length=80) message = models.TextField() created_at = models.DateTimeField(auto_now_add=True) class Meta: ordering = ["-created_at"] verbose_name_plural = "Guestbook entries" def __str__(self) -> str: return f"{self.nickname}: {self.message[:40]}" class Config(models.Model): """Singleton-style global配置(Admin 中 id=1)。""" unlock_at = models.DateTimeField( blank=True, null=True, help_text="已弃用:前端不再按此锁定章节,可留空。", ) together_since = models.DateTimeField( blank=True, null=True, help_text="用于首页「我们在一起多少天多少秒」的起点(建议为正式在一起的时刻,含时区)。", ) site_title = models.CharField( max_length=120, default="Nepal Journey: Our Story", blank=True, ) class Meta: verbose_name_plural = "Config" def __str__(self) -> str: return "Site configuration" def save(self, *args, **kwargs): self.pk = 1 super().save(*args, **kwargs) def delete(self, *args, **kwargs): pass