Files
rssKeeper/backend/models.py
T
congsh 68bba3d9e0 feat: 深色主题UI、错误分类、批量抓取、健康度筛选
- 修复 datetime 时区不一致导致所有API 500错误的问题
- Feeds/Dashboard 页面改为深色表格主题,高对比度文字
- 添加错误类型自动分类(URL失效/被拒绝/超时/DNS失败/SSL错误等12种)
- 新增"下次抓取时间"列,从APScheduler获取
- 新增健康度筛选下拉,修复分页后过滤失效的bug
- "全部抓取"改为同步并发执行,基于当前筛选条件获取所有匹配源
- 新增数据库自动迁移机制,处理增量列变更

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 17:44:54 +08:00

96 lines
3.5 KiB
Python

"""SQLAlchemy 数据模型"""
from datetime import datetime
from sqlalchemy import Column, Integer, String, Text, Boolean, DateTime, ForeignKey
from sqlalchemy.orm import relationship
from database import Base
class Feed(Base):
"""RSS 源"""
__tablename__ = "feeds"
id = Column(Integer, primary_key=True, index=True)
url = Column(String(2048), unique=True, nullable=False, index=True)
title = Column(String(512), default="")
description = Column(Text, default="")
category = Column(String(128), default="")
is_active = Column(Boolean, default=True, index=True)
fetch_interval_minutes = Column(Integer, default=60)
# 抓取统计
last_fetch_at = Column(DateTime, nullable=True)
last_fetch_status = Column(String(20), default="")
last_error = Column(Text, default="")
error_type = Column(String(32), default="")
success_count = Column(Integer, default=0)
fail_count = Column(Integer, default=0)
article_count = Column(Integer, default=0)
created_at = Column(DateTime, default=datetime.utcnow)
# 关联
articles = relationship("Article", back_populates="feed", cascade="all, delete-orphan")
fetch_logs = relationship("FetchLog", back_populates="feed", cascade="all, delete-orphan")
def health_status(self, now: datetime = None):
"""计算健康度
🟢 健康: 成功率 >= 90%, 最近7天有更新
🟡 警告: 成功率 50%-90%, 或超过3天未更新
🔴 异常: 成功率 < 50%, 或超过7天未更新
⚪ 未知: 尚未进行过任何抓取
"""
total = self.success_count + self.fail_count
if total == 0:
return "unknown"
success_rate = self.success_count / total
if now is None:
now = datetime.utcnow()
days_since_last_fetch = None
if self.last_fetch_at:
days_since_last_fetch = (now - self.last_fetch_at).days
if success_rate >= 0.9 and (days_since_last_fetch is None or days_since_last_fetch <= 7):
return "healthy"
elif success_rate >= 0.5 and (days_since_last_fetch is None or days_since_last_fetch <= 7):
return "warning"
else:
return "unhealthy"
class Article(Base):
"""RSS 文章"""
__tablename__ = "articles"
id = Column(Integer, primary_key=True, index=True)
feed_id = Column(Integer, ForeignKey("feeds.id", ondelete="CASCADE"), nullable=False, index=True)
title = Column(String(1024), default="", index=True)
link = Column(String(2048), unique=True, nullable=False, index=True)
author = Column(String(256), default="")
published_at = Column(DateTime, nullable=True, index=True)
content = Column(Text, default="")
summary = Column(Text, default="")
is_read = Column(Boolean, default=False)
created_at = Column(DateTime, default=datetime.utcnow, index=True)
# 关联
feed = relationship("Feed", back_populates="articles")
class FetchLog(Base):
"""抓取日志"""
__tablename__ = "fetch_logs"
id = Column(Integer, primary_key=True, index=True)
feed_id = Column(Integer, ForeignKey("feeds.id", ondelete="CASCADE"), nullable=False, index=True)
status = Column(String(20), nullable=False) # success / fail
articles_fetched = Column(Integer, default=0)
error_message = Column(Text, default="")
response_time_ms = Column(Integer, nullable=True)
created_at = Column(DateTime, default=datetime.utcnow, index=True)
# 关联
feed = relationship("Feed", back_populates="fetch_logs")