University Ranking Backend:代码深度解析(第一部分)

本篇将深入 University Ranking Backend 的代码结构。我们探索应用入口和驱动大学搜索过滤系统的核心逻辑。 🏗️ 整体架构 后端遵循标准的 模型-视图-控制器 (MVC) 模式(其中"视图"是 JSON 响应)。 app.py:初始化应用、注册路由的入口点 routes/:处理 HTTP 请求、解析参数、委托给模型 models/:包含业务逻辑和数据库交互 db/:管理 SQLite 数据库连接 1. 入口点:app.py 这个文件是应用的心脏。它设置 Flask 服务器、配置安全,连接所有组件。 函数:全局作用域 / if __name__ == "__main__": 输入:无(脚本启动时执行) 逻辑: 初始化:创建 Flask 应用实例 CORS 配置:应用 CORS(app) 允许跨域请求。这很关键,因为前端单独托管,需要权限与此 API 通信 蓝图注册:注册三个主蓝图。蓝图如同"插件"为应用添加特定路由: universities_bp(在 /universities) dropdown_bp(在 /dropdown) ranking_detail_bp(在 /subject_rankings) 启动:在端口 10000 启动开发服务器 输出:运行中的 HTTP 服务器 from flask import Flask from routes.universities import universities_bp from routes.dropdown import dropdown_bp from routes.ranking_detail import ranking_detail_bp from flask_cors import CORS app = Flask(__name__) CORS(app) # 注册蓝图 app.register_blueprint(universities_bp, url_prefix="/universities") app.register_blueprint(dropdown_bp, url_prefix="/dropdown") app.register_blueprint(ranking_detail_bp, url_prefix="/subject_rankings") if __name__ == "__main__": app.run(host='0.0.0.0', port=10000) 2. 核心逻辑:models/universities.py 这个文件包含搜索功能的"大脑"。处理复杂的搜索、过滤、排序逻辑。 ...

2025年12月7日

University Ranking Backend:代码深度解析(第二部分)

在 第一部分,我们探讨了核心搜索逻辑和 API 结构。本篇深入 数据层——如何规范化、存储和检索数据。我们还看看驱动后端功能的实用脚本。 1. 数据"胶水":utils/normalize_name.py 从多个来源(QS、US News、Niche)聚合数据的最大挑战是它们命名大学的方式不一。“MIT” 在一个数据集中是"Massachusetts Institute of Technology",在另一个可能是"Mass Inst of Tech"。 这个文件包含标准化名称的逻辑,以便我们能将数据链接在一起。 函数:normalize_name 输入:name(字符串),如"University of California, Berkeley (UCB)" 逻辑: 转小写:全部转小写避免大小写不匹配 清理:删除括号内文本(如缩写)和标点 别名检查:检查已知别名字典(ALIASES)。若输入"mit",自动转换为"massachusetts institute of technology" 输出:清洁、标准化的字符串(如"university of california berkeley") def normalize_name(name: str) -> str: # 转小写 name = name.lower() # 删除括号内文本,如"(MIT)" name = re.sub(r'\(.*?\)', '', name) # 删除标点 name = re.sub(r'[^\w\s]', '', name) # 规范化空格 name = re.sub(r'\s+', ' ', name) if name in ALIASES: # 若名称是别名,替换为全名 name = ALIASES[name] return name.strip() 2. 详细资料逻辑:models/university.py 虽然 models/universities.py(复数)处理列表和搜索,但这个文件处理 单一 大学资料的深度挖掘。 函数:get_university_by_id 这个函数很有趣,因为它必须从 许多 不同表收集数据构建完整资料。 输入:univ_id(整数) 逻辑: 基础信息:从 Universities 表获取主要信息(名称、位置、照片) 翻译:与 University_names_en_to_zh 联接获中文名称 动态排名检索: 查询 sqlite_master 查找数据库中所有以 _Rankings 结尾的表 遍历每张排名表检查该大学是否在其中 这使系统易于扩展——若添加新排名表(如"Mars_University_Rankings"),这函数自动使用它,无需代码改动 统计数据:从 UniversityStats 获取统计信息(学生数等) 输出:包含该大学已知所有信息的大字典 def get_university_by_id(univ_id): conn = get_db_connection() # 第一步:获取大学基础信息 cur = conn.execute(""" SELECT Universities.*, T.chinese_name FROM Universities LEFT JOIN University_names_en_to_zh AS T ON Universities.id = T.id WHERE Universities.id = ? """, (univ_id,)) row = cur.fetchone() if not row: return None university = dict(row) normalized_name = university['normalized_name'] # 第二步:从所有 *_Rankings 表获取排名 cur = conn.execute("SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '%_Rankings'") ranking_tables = [r["name"] for r in cur.fetchall()] rankings = [] for table in ranking_tables: try: cur = conn.execute( f"""SELECT subject, source, rank_value FROM "{table}" WHERE normalized_name = ?""", (normalized_name,) ) rankings += [dict(r) for r in cur.fetchall()] except Exception as e: # 跳过格式错误或不匹配的表 continue # 第三步:从 UniversityStats 获取统计数据 cur = conn.execute( "SELECT type, count, year FROM UniversityStats WHERE normalized_name = ?", (normalized_name,) ) stats = [dict(r) for r in cur.fetchall()] conn.close() rankings = sorted(rankings, key= lambda x: -1 if "global" in x["subject"] or "World" in x["subject"] else x["rank_value"]) # 合并所有信息 university["rankings"] = rankings university["stats"] = stats return university 3. 学科排名:routes/ranking_detail.py 这个路由处理特定学科排名,如"计算机科学"或"医学"。 ...

2025年12月7日