Files
ai-app-database/app/models/folder.py
T
huty f3bd3f68a5
CI — Docker Build & Push / Build & Push Image (push) Failing after 10m15s
新增文件夹功能
2026-04-23 15:45:28 +09:00

85 lines
3.1 KiB
Python

from datetime import datetime
from app.extensions import db
class Folder(db.Model):
__tablename__ = 'folders'
__table_args__ = (
# 同一用户同一父目录下名称唯一
# 注意:MySQL 对 NULL 不强制唯一,根目录重名由路由层补充校验
db.UniqueConstraint('user_id', 'parent_id', 'name',
name='uq_folder_user_parent_name'),
)
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer,
db.ForeignKey('users.id', ondelete='CASCADE'),
nullable=False, index=True)
name = db.Column(db.String(128), nullable=False)
parent_id = db.Column(db.Integer,
db.ForeignKey('folders.id', ondelete='CASCADE'),
nullable=True, index=True)
created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
updated_at = db.Column(db.DateTime, default=datetime.utcnow,
onupdate=datetime.utcnow, nullable=False)
# 自引用关系:父删 → 子自动删
children = db.relationship(
'Folder',
backref=db.backref('parent', remote_side=[id]),
lazy='select',
cascade='all, delete-orphan'
)
# 文件夹内的资源
resources = db.relationship(
'Resource',
backref='folder',
lazy='dynamic',
foreign_keys='Resource.folder_id'
)
# ── 业务方法 ─────────────────────────────────────────────────
def is_ancestor_of(self, target_id: int) -> bool:
"""检测 self 是否是 target_id 的祖先(防止移动到自身子树产生循环引用)"""
visited = set()
current = Folder.query.get(target_id)
while current is not None:
if current.id == self.id:
return True
if current.id in visited:
break
visited.add(current.id)
current = current.parent
return False
def get_breadcrumb(self) -> list:
"""从根到当前节点的路径列表(用于面包屑导航)"""
path, node = [], self
while node is not None:
path.append(node)
node = node.parent
path.reverse()
return path
def to_dict(self) -> dict:
return {
'id': self.id,
'name': self.name,
'parent_id': self.parent_id,
'resource_count': self.resources.count(),
'children': [c.to_dict() for c in sorted(self.children, key=lambda x: x.name)]
}
@staticmethod
def get_user_tree(user_id: int) -> list:
"""返回某用户所有根文件夹的完整树(递归序列化)"""
roots = (Folder.query
.filter_by(user_id=user_id, parent_id=None)
.order_by(Folder.name)
.all())
return [f.to_dict() for f in roots]
def __repr__(self):
return f'<Folder {self.id} {self.name!r}>'