from django.db import models from django_ckeditor_5.fields import CKEditor5Field from users.models import User, Department # Create your models here. from django.db import models from django.core.exceptions import ValidationError class Section(models.Model): name = models.CharField('板块名称', max_length=100, unique=True) code = models.SlugField('唯一标识', max_length=50, unique=True, help_text='用于模板或URL识别,建议英文') parent = models.ForeignKey( 'self', on_delete=models.CASCADE, null=True, blank=True, related_name='subsections', verbose_name='所属主板块' ) order = models.PositiveSmallIntegerField('排序权重', default=0) enabled = models.BooleanField('启用状态', default=True) class Meta: verbose_name = '板块' verbose_name_plural = '板块管理' ordering = ('order', 'name') def __str__(self): if self.parent: return f"{self.parent.name} → {self.name}" return self.name def clean(self): super().clean() # 禁止子板块再设父级(即最多两级) if self.parent and self.parent.parent: raise ValidationError('子板块不能再设置子级,最多只允许一级嵌套。') # 防止自引用 if self.pk and self.parent and self.parent.pk == self.pk: raise ValidationError('板块不能以自身为父级。') @property def is_sub(self): """是否为子板块""" return self.parent is not None @property def is_main(self): """是否为主板块(无父级)""" return self.parent is None class Carousel(models.Model): title = models.CharField("轮播标题", max_length=100) image = models.ImageField("图片", upload_to='carousel/') link_url = models.URLField("跳转链接", blank=True) order = models.IntegerField("排序", default=0) active = models.BooleanField("启用", default=True) class Meta: verbose_name = "轮播图" verbose_name_plural = "轮播管理" class Article(models.Model): title = models.CharField("标题", max_length=200) section = models.ForeignKey(Section, on_delete=models.CASCADE, verbose_name="所属板块") author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, verbose_name="作者") content = CKEditor5Field("正文") # 需安装 django-ckeditor cover = models.ImageField("封面图", upload_to='articles/', blank=True) is_published = models.BooleanField("已发布", default=True) created_at = models.DateTimeField("创建时间", auto_now_add=True) updated_at = models.DateTimeField("更新时间", auto_now=True) class Meta: verbose_name = "文章" verbose_name_plural = "文章管理" def __str__(self): return self.title class Notice(models.Model): title = models.CharField("通知标题", max_length=200) content = CKEditor5Field("通知内容") publisher = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, verbose_name="发布人") target_departments = models.ManyToManyField(Department, blank=True, verbose_name="接收部门") # 可指定发给哪些部门 require_sign = models.BooleanField("是否需要签收", default=False) is_published = models.BooleanField("已发布", default=True) created_at = models.DateTimeField("发布时间", auto_now_add=True) updated_at = models.DateTimeField("更新时间", auto_now=True) class Meta: verbose_name = "通知" verbose_name_plural = "通知管理" def __str__(self): return self.title class NoticeReceipt(models.Model): """签收记录""" notice = models.ForeignKey(Notice, on_delete=models.CASCADE, related_name='receipts') user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="签收人") signed_at = models.DateTimeField("签收时间", auto_now_add=True) class Meta: unique_together = ('notice', 'user') # 防止重复签收 verbose_name = "签收记录" verbose_name_plural = "签收管理" def __str__(self): return f"{self.user.cname} 已签收《{self.notice.title}》"