from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, LargeBinary from sqlalchemy.orm import relationship from datetime import datetime import os from . import Base class Attachment(Base): """附件模型""" __tablename__ = 'attachments' id = Column(Integer, primary_key=True) email_id = Column(Integer, ForeignKey('emails.id'), nullable=False, index=True) filename = Column(String(255), nullable=False) content_type = Column(String(100), nullable=True) size = Column(Integer, nullable=False, default=0) storage_path = Column(String(500), nullable=True) # 用于文件系统存储 content = Column(LargeBinary, nullable=True) # 用于小型附件的直接存储 created_at = Column(DateTime, default=datetime.utcnow) # 关联关系 email = relationship("Email", back_populates="attachments") @property def is_stored_in_fs(self): """判断附件是否存储在文件系统中""" return bool(self.storage_path and not self.content) def save_to_filesystem(self, content, base_path): """将附件保存到文件系统""" # 确保目录存在 os.makedirs(base_path, exist_ok=True) # 创建文件路径 file_path = os.path.join( base_path, f"{self.email_id}_{self.id}_{self.filename}" ) # 写入文件 with open(file_path, 'wb') as f: f.write(content) # 更新对象属性 self.storage_path = file_path self.size = len(content) self.content = None # 清空内存中的内容 return file_path def get_content(self, attachments_dir=None): """获取附件内容,无论是从数据库还是文件系统""" if self.content: return self.content if self.storage_path and os.path.exists(self.storage_path): with open(self.storage_path, 'rb') as f: return f.read() return None def to_dict(self): """转换为字典,用于API响应""" return { "id": self.id, "email_id": self.email_id, "filename": self.filename, "content_type": self.content_type, "size": self.size, "created_at": self.created_at.isoformat() if self.created_at else None }