from sqlalchemy import Column, Integer, String, BigInteger, DateTime, ForeignKey, Boolean, Text from sqlalchemy.orm import relationship from sqlalchemy.sql import func from app.core.database import Base class File(Base): __tablename__ = "files" id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("users.id"), nullable=False, index=True) # 文件基本信息 filename = Column(String(255), nullable=False, index=True) original_filename = Column(String(255), nullable=False) # 用户上传时的原始文件名 file_path = Column(String(500), nullable=False) # 服务器上的存储路径 file_size = Column(BigInteger, nullable=False) # 文件大小(字节) mime_type = Column(String(100), nullable=False) # 文件MIME类型 file_hash = Column(String(64), nullable=False, index=True) # SHA-256哈希,用于去重和完整性检查 # 文件状态 is_public = Column(Boolean, default=False) # 是否公开分享 download_count = Column(BigInteger, default=0) # 下载次数 # 文件元数据 description = Column(Text, nullable=True) # 文件描述 tags = Column(Text, nullable=True) # 标签,用逗号分隔 # 时间戳 created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now()) last_accessed_at = Column(DateTime(timezone=True), nullable=True) # 关联关系 user = relationship("User", back_populates="files") def __repr__(self): return f"" def to_dict(self): return { "id": self.id, "user_id": self.user_id, "filename": self.filename, "original_filename": self.original_filename, "file_size": self.file_size, "mime_type": self.mime_type, "file_hash": self.file_hash, "is_public": self.is_public, "download_count": self.download_count, "description": self.description, "tags": self.tags, "created_at": self.created_at.isoformat() if self.created_at else None, "updated_at": self.updated_at.isoformat() if self.updated_at else None, "last_accessed_at": self.last_accessed_at.isoformat() if self.last_accessed_at else None, } def get_file_extension(self) -> str: """获取文件扩展名""" return self.filename.split('.')[-1].lower() if '.' in self.filename else '' def is_image(self) -> bool: """判断是否为图片文件""" return self.mime_type.startswith('image/') def is_document(self) -> bool: """判断是否为文档文件""" document_types = [ 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'text/plain', 'text/csv' ] return self.mime_type in document_types def get_size_formatted(self) -> str: """获取格式化的文件大小""" for unit in ['B', 'KB', 'MB', 'GB']: if self.file_size < 1024.0: return f"{self.file_size:.1f} {unit}" self.file_size /= 1024.0 return f"{self.file_size:.1f} TB"