Files
chunyu_project/air_quality/views.py
T
2026-08-05 23:59:15 +08:00

189 lines
7.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import requests
from datetime import datetime
from rest_framework.permissions import AllowAny
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from chunyu_project.common_schemas import success_response, error_response
GEOCODING_URL = "https://geocoding-api.open-meteo.com/v1/search"
AIR_QUALITY_URL = "https://air-quality-api.open-meteo.com/v1/air-quality"
def get_air_quality_level(pm2_5):
"""
根据PM2.5浓度获取空气质量等级
"""
if pm2_5 <= 10:
return "优"
elif pm2_5 <= 25:
return "良"
elif pm2_5 <= 50:
return "轻度污染"
elif pm2_5 <= 75:
return "中度污染"
else:
return "重度污染"
class AirQualityView(APIView):
"""
空气质量查询视图 - 基于 Open-Meteo Air Quality API(免费,无需API Key)
"""
permission_classes = [AllowAny]
@swagger_auto_schema(
tags=['Air Quality'],
operation_summary='获取空气质量信息(GET方式)',
operation_description='通过城市名称获取实时空气质量信息,支持PM2.5、PM10、臭氧、二氧化氮等指标',
manual_parameters=[
openapi.Parameter(
'city',
openapi.IN_QUERY,
description='城市名称(支持中文、英文,如:北京、Beijing、上海、Shanghai)',
type=openapi.TYPE_STRING,
required=True
),
openapi.Parameter(
'lang',
openapi.IN_QUERY,
description='返回语言(默认:zh_cn)',
type=openapi.TYPE_STRING,
required=False,
enum=['zh_cn', 'en']
),
],
responses={200: success_response, 400: error_response, 404: error_response, 502: error_response}
)
def get(self, request):
city = request.GET.get('city', '').strip()
lang = request.GET.get('lang', 'zh_cn').strip()
if not city:
return Response(
{"code": 400, "message": "参数错误:city不能为空", "data": None},
status=status.HTTP_400_BAD_REQUEST
)
return self._fetch_air_quality(city, lang)
@swagger_auto_schema(
tags=['Air Quality'],
operation_summary='获取空气质量信息(POST方式)',
operation_description='通过城市名称获取实时空气质量信息,支持PM2.5、PM10、臭氧、二氧化氮等指标',
request_body=openapi.Schema(
type=openapi.TYPE_OBJECT,
required=['city'],
properties={
'city': openapi.Schema(type=openapi.TYPE_STRING, description='城市名称(支持中文、英文)'),
'lang': openapi.Schema(type=openapi.TYPE_STRING, description='返回语言(默认:zh_cn)', enum=['zh_cn', 'en']),
}
),
responses={200: success_response, 400: error_response, 404: error_response, 502: error_response}
)
def post(self, request):
city = request.data.get('city', '').strip() if isinstance(request.data, dict) else ''
lang = request.data.get('lang', 'zh_cn').strip() if isinstance(request.data, dict) else 'zh_cn'
if not city:
return Response(
{"code": 400, "message": "参数错误:city不能为空", "data": None},
status=status.HTTP_400_BAD_REQUEST
)
return self._fetch_air_quality(city, lang)
def _fetch_air_quality(self, city, lang):
"""
调用 Open-Meteo Air Quality API 获取空气质量数据
"""
try:
# 第一步:通过地理编码API获取城市坐标
geo_params = {
'name': city,
'count': 1,
'language': 'zh' if lang == 'zh_cn' else 'en',
'format': 'json'
}
geo_response = requests.get(GEOCODING_URL, params=geo_params, timeout=10)
if geo_response.status_code != 200:
return Response(
{"code": 502, "message": "地理编码服务异常,请稍后重试", "data": None},
status=status.HTTP_502_BAD_GATEWAY
)
geo_data = geo_response.json()
results = geo_data.get('results', [])
if not results:
return Response(
{"code": 404, "message": f"未找到城市:{city},请检查城市名称是否正确", "data": None},
status=status.HTTP_404_NOT_FOUND
)
location = results[0]
latitude = location.get('latitude')
longitude = location.get('longitude')
city_name = location.get('name', city)
country = location.get('country', '')
# 第二步:获取空气质量数据
air_quality_params = {
'latitude': latitude,
'longitude': longitude,
'current': 'pm10,pm2_5,carbon_monoxide,nitrogen_dioxide,sulphur_dioxide,ozone,us_aqi',
'timezone': 'auto'
}
aq_response = requests.get(AIR_QUALITY_URL, params=air_quality_params, timeout=10)
if aq_response.status_code != 200:
return Response(
{"code": 502, "message": "空气质量服务异常,请稍后重试", "data": None},
status=status.HTTP_502_BAD_GATEWAY
)
aq_data = aq_response.json()
current = aq_data.get('current', {})
pm2_5 = current.get('pm2_5', 0)
# 构建响应
air_quality_info = {
'city': city_name,
'country': country,
'pm2_5': pm2_5,
'pm10': current.get('pm10', 0),
'ozone': current.get('ozone', 0),
'nitrogen_dioxide': current.get('nitrogen_dioxide', 0),
'sulphur_dioxide': current.get('sulphur_dioxide', 0),
'carbon_monoxide': current.get('carbon_monoxide', 0),
'air_quality_level': get_air_quality_level(pm2_5),
'updated_at': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
}
return Response(
{"code": 200, "message": "success", "data": air_quality_info},
status=status.HTTP_200_OK
)
except requests.exceptions.Timeout:
return Response(
{"code": 502, "message": "请求超时,请稍后重试", "data": None},
status=status.HTTP_502_BAD_GATEWAY
)
except requests.exceptions.ConnectionError:
return Response(
{"code": 502, "message": "网络连接异常,请检查网络后重试", "data": None},
status=status.HTTP_502_BAD_GATEWAY
)
except Exception as e:
return Response(
{"code": 500, "message": f"服务器内部错误:{str(e)}", "data": None},
status=status.HTTP_500_INTERNAL_SERVER_ERROR
)