(一).灾情查询接口
(1)链接数据库后使用结合SQL语句进行查询(不推荐使用,可能数据库会有注入风险):
<1>API代码如下:
from django.http import JsonResponse # 从Django的http模块导入JsonResponse类,用于返回JSON格式的响应。
from app_query.models import ApiDisaster_internet,ApiDisaster_internet_image
from app_query.models import ApiVulnerability_curve_building,ApiVulnerability_curve_cotton
import datetime # 导入python的日期处理模块。
import psycopg2 # 导入用于连接Postgresql数据库的库。
### 查询灾情数据接口
def disaster_query(request):
### 通过浏览器中输入,从GET请求查询中获取特定的参数值,如果没有提供对应的参数,就将变量设置为None。
type = request.GET.get('type', None)
region = request.GET.get('region', None)
start_time_str = request.GET.get('start_time', None)
end_time_str = request.GET.get('end_time', None)
# 打印接收到的参数信息(用于调试)
print(
f"Received parameters: type={type}, region={region}, start_time={start_time_str}, end_time={end_time_str}")
# 连接数据库
dbConn = psycopg2.connect(
dbname="data_agg", # 连接名为data_agg的数据库。
user='postgres',
password='QYkj$2023$$',
host='43.138.35.113',
port=5432
)
cursor = dbConn.cursor() # 创建一个游标对象,由于执行SQL查询。
# 初始化一个 SQL 查询语句
query = "SELECT * FROM disaster_internet" # 用于后面将查询条件添加到这条查询语句中。
# 创建一个空列表condition,用于存储后续的查询条件
conditions = []
### 如果有disaster_type参数,将条件disaster_type='{disaster_type}'添加到condition列表中,这意味这如果指定了灾害类型,查询将只选择该类型的记录。
if type:
conditions.append(f"type = '{type}'")
### 如果有 address参数,进行地址的模糊匹配查询
if region:
address_condition = "" # 初始化一个空字符串,用于构建地址查询条件。
for char in region: # 遍历地址字符串(address)中的每个字符,并将其赋值给变量char。
if address_condition:
address_condition += " AND " # 如果地址不为空,添加 AND 连接符。
address_condition += f"region LIKE '%{char}%'" # 构建模糊匹配的地址查询条件,例如 address LIKE '%武%','%汉%'等,对每个字符进行模糊匹配。
if address_condition:
conditions.append(f"({address_condition})") # 如果地址条件不为空,将其添加到 conditions 列表。
# 如果有start_datetime_str和end_datetime_str参数,将字符串转换为datetime对象后,添加时间范围条件"datetime BETWEEN '{start_datetime}' AND '{end_datetime}'",用于筛选在指定时间范围内的记录。
if start_time_str and end_time_str:
# 如果有 start_datetime_str 和 end_datetime_str 参数,将其转换为 datetime 对象。
start_time = datetime.datetime.strptime(start_time_str, '%Y-%m-%d')
end_time = datetime.datetime.strptime(end_time_str, '%Y-%m-%d')
# 添加时间范围查询条件到 condition 列表。
conditions.append(f"datetime BETWEEN '{start_time}' AND '{end_time}'")
# 如果有条件存在,将条件添加到初始查询语句中,使用WHERE和AND连接多个条件
if conditions:
query += " WHERE " + " AND ".join(conditions) # 如果 condition 列表不为空,将条件添加到查询语句中。
# 执行构建好的SQL查询语句
cursor.execute(query)
# 获取查询结果的所有行
rows = cursor.fetchall() # 从数据库游标中获取所有查询结果的行,并将其存储在变量rows中。
# 将查询结果转换为一个列表,列表中的每一个元素是一个字典,包含灾害类型,地址和时间三个字段的值,查询结果的每一行中提取的列值。
result_data = []
if rows:
for row in rows:
item = {
'disaster_id': row[0],
'type': row[1],
'region': row[2],
'datetime': row[3],
'longitude': row[4],
'latitude': row[5],
'title': row[6],
'abstract': row[7],
'src_abstract': row[8],
'src_content': row[9],
'ai_abstract': row[10],
'ai_engine': row[11],
'ai_content': row[12],
'image_url': row[13],
}
result_data.append(item) # 如果有查询结果(result),则将每一行item字典添加到 result 列表中。
cursor.close() # 关闭游标。
dbConn.close() # 关闭数据库连接。
<2>models代码如下:
from django.db import models
# Create your models here.
class ApiDisaster_internet(models.Model):
disaster_id = models.UUIDField(primary_key=True, verbose_name='灾害id')
type = models.CharField(max_length=255, verbose_name='灾害类型')
region = models.CharField(max_length=255, verbose_name='灾害区域')
datatime = models.DateTimeField(verbose_name='灾害时间')
longitude = models.CharField(max_length=255, verbose_name='经度')
latitude = models.CharField(max_length=255, verbose_name='纬度')
title = models.CharField(max_length=255, verbose_name='标题')
abstract = models.CharField(max_length=255, verbose_name='摘要')
# description = models.CharField(max_length=255, verbose_name='描述信息')
src_abstract = models.CharField(max_length=255, verbose_name='原始摘要')
src_content = models.TextField(verbose_name='原始描述', null=False)
ai_abstract = models.CharField(max_length=255, verbose_name='AI提取后的摘要')
ai_content = models.JSONField(verbose_name='AI提取后结构化的数据')
ai_engine = models.CharField(max_length=32, verbose_name='存储是由哪个AI提取的')
image_url = models.CharField(max_length=255, verbose_name='图片路径')
class Meta:
db_table = 'disaster_internet'
(2)基于Django框架自带的ORM进行查询(推荐使用):
### 灾情数据查询接口
# 从请求对象中获取查询参数
def disaster_query(request):
type_param = request.GET.get('type', None)
region_param = request.GET.get('region', None)
start_time_str = request.GET.get('start_time', None)
end_time_str = request.GET.get('end_time', None)
# 用于调试(打印接收到的查询参数)
print(f"Received parameters: type={type_param}, region={region_param}, start_time={start_time_str}, end_time={end_time_str}")
# 创建一个查询集 queryset,并获取 ApiDisaster_internet 模型的所有对象。
queryset = ApiDisaster_internet.objects.all()
if type_param:
queryset = queryset.filter(type=type_param)
if region_param:
# 改进地区匹配逻辑,将输入的地区字符串按空格分割后进行多个关键词的模糊匹配
region_keywords = region_param.split() # 将地区参数字符串按空格进行分隔(若无空格则将如湖北省武汉市汉口江滩分割为['湖北省','武汉市','汉口江滩'])
region_condition = models.Q()
for keyword in region_keywords:
region_condition &= models.Q(region__contains=keyword) # 构建一个复合查询,通过与操作使得最终的查询结果满足所有的关键词条件。
if region_condition:
queryset = queryset.filter(region_condition)
if start_time_str and end_time_str:
utc_timezone = pytz.utc # 设置时区对象。
start_time = datetime.strptime(start_time_str, '%Y-%m-%d').replace(tzinfo=utc_timezone)
end_time = datetime.strptime(end_time_str, '%Y-%m-%d').replace(tzinfo=utc_timezone)
queryset = queryset.filter(datetime__range=(start_time, end_time))
result_data = []
if queryset.exists():
result_data = list(queryset.values())
if result_data:
response_data = {
"status": 200,
"result": result_data,
"message": "OK"
}
return JsonResponse(response_data, safe=False)
else:
response_data = {
"status": 404,
"result": [],
"message": "No results found"
}
return JsonResponse(response_data, safe=False)
(二).损失曲线查询结果
(1)连接数据库之结合SQL语句对表进行查询:
<1>API代码如下:
### 损失曲线查询接口
def curve_query(request):
type_param = request.GET.get('type', None)
if type_param not in ['building', 'cotton']:
return JsonResponse({"status": 400, "result": [], "message": "Invalid type parameter."}, safe=False)
# 连接数据库
dbConn = psycopg2.connect(
dbname="data_agg", # 连接名为data_agg的数据库。
user='postgres',
password='QYkj$2023$$',
host='43.138.35.113',
port=5432
)
cursor = dbConn.cursor() # 创建一个游标对象,由于执行SQL查询。
model_classes = {
'building': ApiVulnerability_curve_building,
'cotton': ApiVulnerability_curve_cotton
}
model = model_classes[type_param]
query = f"SELECT * FROM {model._meta.db_table}"
cursor.execute(query)
rows = cursor.fetchall()
result_data = []
for row in rows:
item = {}
for index, field in enumerate(model._meta.fields):
item[field.name] = row[index]
result_data.append(item)
cursor.close()
dbConn.close()
return JsonResponse({"status": 200, "result": result_data, "message": "Success"}, safe=False)
<2>models代码如下:
class ApiVulnerability_curve_building(models.Model):
水深 = models.DecimalField(max_digits=10, decimal_places=2, primary_key=True)
砖混结构农村住房 = models.FloatField()
砖结构农村住房 = models.FloatField()
砖混结构城市住房 = models.FloatField()
砖结构城市住房 = models.FloatField()
砖混结构商业用房 = models.FloatField()
砖结构商业用房 = models.FloatField()
框架结构商业用房 = models.FloatField()
class Meta:
db_table = 'VULNERABILITY_CURVE_BUILDING'
class ApiVulnerability_curve_cotton(models.Model):
duration = models.DecimalField(max_digits=10, decimal_places=1, primary_key=True)
loss = models.FloatField()
class Meta:
db_table = 'VULNERABILITY_CURVE_COTTON'
(2)基于Django自带的ORM框架进行查询:
### 损失曲线查询接口
def curve_query(request):
type_param = request.GET.get('type', None)
if type_param not in ['building', 'cotton']:
return JsonResponse({"status": 400, "result": [], "message": "Invalid type parameter."}, safe=False)
model = None
if type_param == 'building':
model = ApiVulnerability_curve_building
elif type_param == 'cotton':
model = ApiVulnerability_curve_cotton
# 选取选定的models中的所有对象,并转换为字典列表形式赋值给result_data中。
result_data = list(model.objects.all().values())
### 定义一个字典field_mappings,用于将中文列名映射为英文列名。
field_mappings = {
'building': {
"水深": "water_depth",
"砖混结构农村住房": "rural_housing_with_brick_concrete_structure",
"砖结构农村住房": "rural_housing_with_brick_structure",
"砖混结构城市住房": "urban_housing_with_brick_concrete_structure",
"砖结构城市住房": "urban_housing_with_brick_structure",
"砖混结构商业用房": "commercial_building_with_brick_concrete_structure",
"砖结构商业用房": "commercial_building_with_brick_structure",
"框架结构商业用房": "commercial_building_with_frame_structure"
},
'cotton':{} # 棉花表是英文,不需要转换,所以留的空字典。
}
new_result_data = []
for item in result_data:
new_item = {}
mapping = field_mappings[type_param]
for key, value in item.items(): # key:键(数据库表中的列名),value:对应列的值。
if key in mapping: # 检查当前的遍历到的key(列名)是否存在于映射字典mapping中(如果key在mapping中,说明这个列名有对应的英文映射)。
new_item[mapping[key]] = value # 将原始数据中的值赋给新字典中以英文列名(mapping[key])作为键的位置。
else:
new_item[key] = value # 如果不存在于映射字典中(如cotton:{}这个空字典),我们就直接使用原始的键key(原始的列名)。
new_result_data.append(new_item) # 将处理后的字典new_item添加到列表new_result_data中。
return JsonResponse({"status": 200, "result": new_result_data, "message": "Success"}, safe=False)