events/standings 创建 Team 前均经 team_names.normalize(已有,确认), TeamRepository.get_or_create 收敛为归一化唯一咽喉 + info 日志。 新增 team_aliases 表(NFKD 归一别名 → teams.id FK CASCADE), 定位三步链:normalize(name) → teams.name → team_aliases → insert。 不自动合并历史重复队;提供 POST /api/v1/admin/teams/aliases 显式添加。 迁移 0020_team_aliases + Admin 别名管理端点(admin_teams.py)。 全量测试 270 通过。
61 lines
2.3 KiB
Python
61 lines
2.3 KiB
Python
"""后台管理:球队别名管理(只读列表 + 添加别名)。
|
|
|
|
归一名(teams.name)是球队唯一键;别名(team_aliases)是同一球队的不同写法
|
|
(大小写/译名/缩写)到归一后 teams.id 的映射。入库时 normalize(name) 依次查
|
|
teams.name 与 team_aliases,命中即复用,避免重复 Team。
|
|
|
|
不自动合并历史重复队;需显式添加别名(或先 SQL/再经由此接口)。
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy import desc, select
|
|
|
|
from src.api.deps import require_admin
|
|
from src.api.schemas import TeamAliasIn, TeamAliasOut
|
|
from src.db.base import AsyncSession, get_db_read
|
|
from src.db.models import Team, TeamAlias
|
|
from src.db.repositories import TeamRepository
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
router = APIRouter(prefix="/api/v1/admin", tags=["admin"], dependencies=[Depends(require_admin)])
|
|
|
|
|
|
@router.get("/teams/aliases", response_model=list[TeamAliasOut])
|
|
async def list_team_aliases(db: AsyncSession = Depends(get_db_read)):
|
|
"""列出所有球队别名(最新在前)。"""
|
|
rows = (await db.execute(select(TeamAlias).order_by(desc(TeamAlias.created_at)).limit(200))).scalars().all()
|
|
return [
|
|
TeamAliasOut(
|
|
alias_normalized=r.alias_normalized,
|
|
team_id=r.team_id,
|
|
original_alias=r.original_alias,
|
|
)
|
|
for r in rows
|
|
]
|
|
|
|
|
|
@router.post("/teams/aliases", response_model=TeamAliasOut, status_code=201)
|
|
async def add_team_alias(req: TeamAliasIn, db: AsyncSession = Depends(get_db_read)):
|
|
"""为已有 Team 添加别名(幂等:重复添加会更新指向)。
|
|
|
|
不自动合并历史重复队。若需合并 A→B:先为 A 的归一名添加别名指向 B,
|
|
再人工确认 A 是否仍有独立引用。
|
|
"""
|
|
# 校验目标 Team 存在
|
|
team = await db.get(Team, req.team_id)
|
|
if team is None:
|
|
raise HTTPException(404, f"目标 Team 不存在: id={req.team_id}")
|
|
|
|
repo = TeamRepository(db)
|
|
row = await repo.add_alias(req.alias, req.team_id)
|
|
logger.info("添加 Team 别名: %s -> team_id=%s", req.alias, req.team_id)
|
|
return TeamAliasOut(
|
|
alias_normalized=row.alias_normalized,
|
|
team_id=row.team_id,
|
|
original_alias=row.original_alias,
|
|
)
|