update. 完成前端页面展示、列表和详情页
update. 调整融合主菜单与板块 update. 分离新闻模块
This commit is contained in:
+131
-14
@@ -1,27 +1,144 @@
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
|
||||
from common.base import BaseEntity
|
||||
|
||||
|
||||
# Create your models here.
|
||||
class MainMenu(models.Model):
|
||||
title = models.CharField("菜单标题", max_length=50)
|
||||
url = models.CharField("链接地址", max_length=200, help_text="如 /news/ 或 外链 https://xxx")
|
||||
is_external = models.BooleanField("是否外链", default=False)
|
||||
parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, verbose_name="父菜单")
|
||||
order = models.IntegerField("排序", default=0)
|
||||
visible = models.BooleanField("是否显示", default=True)
|
||||
|
||||
|
||||
# --- 新增:友情链接分类模型 ---
|
||||
class LinkCategory(BaseEntity):
|
||||
name = models.CharField("分类名称", max_length=50, unique=True) # 分类名,如"政府网站"
|
||||
code = models.SlugField("分类代码", max_length=50, unique=True, help_text="用于前端模板调用的标识,如 'gov', 'fire'")
|
||||
order = models.IntegerField("显示排序", default=0) # 分类本身的排序
|
||||
is_active = models.BooleanField("是否启用", default=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "主菜单"
|
||||
verbose_name_plural = "主菜单管理"
|
||||
verbose_name = "友链分类"
|
||||
verbose_name_plural = "友链分类"
|
||||
ordering = ['order']
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
return self.name
|
||||
|
||||
|
||||
class FooterLink(models.Model):
|
||||
title = models.CharField("链接文字", max_length=50)
|
||||
url = models.URLField("链接地址")
|
||||
# --- 修改:友情链接模型 ---
|
||||
class FriendLink(BaseEntity):
|
||||
# 1. 关联到新的分类模型(一对多关系:一个分类下有多个链接)
|
||||
category = models.ForeignKey(
|
||||
LinkCategory,
|
||||
on_delete=models.CASCADE, # 如果分类被删,关联的链接也删除
|
||||
verbose_name="所属分类",
|
||||
related_name='links' # 反向查询名称,方便后续调用
|
||||
)
|
||||
|
||||
name = models.CharField("网站名称", max_length=100)
|
||||
url = models.URLField("链接地址", max_length=200)
|
||||
|
||||
# 2. 排序和状态
|
||||
order = models.IntegerField("排序", default=0)
|
||||
is_active = models.BooleanField("是否启用", default=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "页脚链接"
|
||||
verbose_name = "友情链接"
|
||||
verbose_name_plural = "友链管理"
|
||||
ordering = ['order', '-created_at']
|
||||
|
||||
def __str__(self):
|
||||
return f"[{self.category.name}] {self.name}"
|
||||
|
||||
|
||||
class MainMenu(BaseEntity):
|
||||
# --- 基础信息 ---
|
||||
title = models.CharField("标题", max_length=100)
|
||||
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='children',
|
||||
verbose_name="父级节点"
|
||||
)
|
||||
|
||||
# --- 菜单特有属性 ---
|
||||
# 只有顶级节点(主菜单)才需要填写这个,子节点作为板块时通常不需要跳转链接
|
||||
url = models.CharField("链接地址", max_length=200, blank=True, help_text="如 /menu/news.html 或 外链")
|
||||
is_external = models.BooleanField("是否外链", default=False)
|
||||
is_carousel = models.BooleanField("轮播图", default=False)
|
||||
|
||||
# --- 通用属性 ---
|
||||
order = models.PositiveSmallIntegerField("排序权重", default=0)
|
||||
visible = models.BooleanField("显示状态", default=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "站点导航"
|
||||
verbose_name_plural = "站点导航"
|
||||
ordering = ('order', 'title')
|
||||
|
||||
def __str__(self):
|
||||
# 显示层级路径,例如:新闻中心 → 国内新闻
|
||||
if self.parent:
|
||||
return f"{self.parent.title} → {self.title}"
|
||||
return self.title
|
||||
|
||||
def clean(self):
|
||||
super().clean()
|
||||
# 限制层级:最多 2 级
|
||||
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 not self.parent
|
||||
|
||||
@property
|
||||
def active_children(self):
|
||||
"""
|
||||
获取当前节点下可见的子节点(用于前端导航渲染)
|
||||
"""
|
||||
return self.children.filter(visible=True)
|
||||
|
||||
|
||||
class FooterLink(BaseEntity):
|
||||
title = models.CharField("页脚信息", max_length=50)
|
||||
address = models.CharField("单位地址", max_length=200)
|
||||
postal = models.CharField("邮编", default="")
|
||||
telephone = models.CharField("服务热线", default="")
|
||||
fax = models.CharField("传真", default="")
|
||||
unit = models.CharField("版权单位", default="")
|
||||
filing = models.CharField("备案号", default="")
|
||||
official_account = models.ImageField("公众号二维码", default="", upload_to='carousel/')
|
||||
weibo = models.ImageField("微博二维码", default="", upload_to='carousel/')
|
||||
is_active = models.BooleanField("生效", default=False)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "页脚信息"
|
||||
verbose_name_plural = "页脚管理"
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.title} - 状态:{'使用中' if self.is_active else '已停用'}"
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
# 1. 如果当前这条数据被标记为“生效” (is_active=True)
|
||||
if self.is_active:
|
||||
# 2. 将数据库中【除了当前这条】以外的所有 FooterLink 都更新为“不生效”
|
||||
# self.pk 是当前对象的唯一标识
|
||||
FooterLink.objects.exclude(pk=self.pk).update(is_active=False)
|
||||
|
||||
# 3. 执行正常的保存操作
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
Reference in New Issue
Block a user