diff --git a/src/moldinsight/services/experience_feedback_service.py b/src/moldinsight/services/experience_feedback_service.py index dbd48c4..c12138c 100644 --- a/src/moldinsight/services/experience_feedback_service.py +++ b/src/moldinsight/services/experience_feedback_service.py @@ -223,7 +223,9 @@ class ExperienceFeedbackService: role_code = "user" # 6. 写 ExperienceFeedback - now = datetime.now(timezone.utc) + # expires_at 列是 naive TIMESTAMP(sa.DateTime()),asyncpg 拒绝 aware datetime + # (DataError → 提交反馈 500);存库/比较统一 naive UTC(同 auth last_login 修复) + now = datetime.now(timezone.utc).replace(tzinfo=None) new_ttl = now + timedelta(days=FEEDBACK_TTL_DAYS) feedback = ExperienceFeedback( processing_task_id=processing_task.id, @@ -274,7 +276,8 @@ class ExperienceFeedbackService: 排除 expires_at < now() 的过期反馈;按 material_family + is_foam 锚定; 按 scheme_axis 聚合(adopted/rejected/adjust 计数 + 加权 confidence)。 """ - now = datetime.now(timezone.utc) + # 同上:expires_at 是 naive TIMESTAMP,SQL 参数也不能传 aware datetime + now = datetime.now(timezone.utc).replace(tzinfo=None) is_foam_str = "true" if is_foam else "false" mat_lower = (material_name or "").lower() if "al" in mat_lower and "si" in mat_lower: diff --git a/src/shared/services/auth_service.py b/src/shared/services/auth_service.py index f652c30..ed02ae8 100644 --- a/src/shared/services/auth_service.py +++ b/src/shared/services/auth_service.py @@ -142,7 +142,11 @@ async def authenticate_user(db_session: AsyncSession, username: str, password: s if not verify_password(password, user.hashed_password): return None - user.last_login = datetime.now(timezone.utc) + # last_login 列是 TIMESTAMP WITHOUT TIME ZONE(sa.DateTime()),asyncpg 拒绝写入 + # 带 tzinfo 的 datetime(DataError → 登录 500):批次5 弃用清理把 utcnow() 换成 + # aware 时间后,任何一次成功登录都会在 commit 处炸掉。存库统一 naive UTC, + # JWT exp(上方 create_access_token)不受影响,仍用 aware。 + user.last_login = datetime.now(timezone.utc).replace(tzinfo=None) await db_session.commit() return user