Files
full-stack-doc/backend/app/models/file.py
2025-10-14 20:05:29 +08:00

86 lines
3.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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"<File(id={self.id}, filename='{self.filename}', user_id={self.user_id})>"
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"