Django开发天气应用避免KeyError的更优实现方式
Django天气应用输入容错优化方案
现有代码可优化点
- 冗余的while循环:判断输入是否为空、城市是否匹配的逻辑仅需单次判断,不需要while循环加break的写法
- 城市校验逻辑存在bug:将城市匹配结果转成字符串做包含判断,会出现子串误匹配问题
- 变量未初始化:GET请求访问首页时
city变量未定义,会直接抛出NameError - 未覆盖接口异常场景:仅做本地城市校验无法覆盖第三方接口返回错误、超时、无权限等情况,直接取返回值的键仍会触发KeyError
- 重复开销:每次POST请求都重新实例化
GeonamesCache,没有必要
优化后代码
from django.shortcuts import render import requests from datetime import datetime import geonamescache # 全局初始化资源,避免每次请求重复加载 gc = geonamescache.GeonamesCache() DEFAULT_CITY = "Amsterdam" WEATHER_API = 'https://api.openweathermap.org/data/2.5/weather' API_KEY = 'MY_KEY' def home(request): city = DEFAULT_CITY error_msg = None # 处理POST查询请求 if request.method == "POST": # 安全取POST参数,自动去除首尾空白字符 input_city = request.POST.get('search-city', '').strip() if not input_city: error_msg = "输入不能为空,已展示默认城市天气" else: # 直接判断匹配列表是否为空,避免字符串匹配的误判问题 match_result = gc.get_cities_by_name(input_city.title()) if match_result: city = input_city else: error_msg = "未匹配到对应城市,已展示默认城市天气" # 初始化返回给模板的默认数据 weather_data = { 'description': '暂无数据', 'temp': '暂无数据', 'icon': '', 'day': datetime.now().strftime("%d/%m/%Y %H:%M"), 'country': '', 'city': city, 'error_msg': error_msg } # 接口请求全链路加异常捕获 try: req_params = { 'q': city, 'appid': API_KEY, 'units': 'metric' } # 加超时避免请求卡死 resp = requests.get(url=WEATHER_API, params=req_params, timeout=10) # 状态码非200直接抛异常 resp.raise_for_status() res = resp.json() # 用get方法安全取值,不存在则用默认值,彻底避免KeyError weather_data['city'] = res.get('name', city) weather_info = res.get('weather', [{}])[0] weather_data['description'] = weather_info.get('description', '暂无天气描述') weather_data['icon'] = weather_info.get('icon', '') main_data = res.get('main', {}) weather_data['temp'] = main_data.get('temp', '暂无温度数据') sys_data = res.get('sys', {}) weather_data['country'] = sys_data.get('country', '') except Exception as e: weather_data['error_msg'] = f"天气查询失败:{str(e)}" return render(request, 'weatherapp/home.html', weather_data)
核心优化逻辑
- 移除所有无意义的while循环,用线性分支判断完成输入校验,逻辑可读性更高
- 全局初始化城市缓存、常量配置,减少重复实例化的性能开销
- 用
request.POST.get()安全取参,配合strip()过滤全空格的无效输入 - 城市校验直接判断匹配列表是否非空,替代原有的字符串包含判断,避免子串误判
- 提前初始化默认城市变量,兼容GET请求访问场景,不会出现变量未定义的错误
- 接口请求增加超时、状态码校验,全链路捕获异常
- 解析接口返回值时统一用
.get()方法取值,为每个字段设置兜底默认值,从根源避免KeyError - 增加错误提示字段,前端可以直接展示提示信息,用户体验更好
内容的提问来源于stack exchange,提问作者manos
相关产品推荐
相关产品推荐

