|
|
|
|
@ -0,0 +1,161 @@
|
|
|
|
|
# Create your views here. #zqx: Django视图文件标准注释,标记视图代码开始
|
|
|
|
|
# 导入所需的Python标准库和第三方库 #zqx: 导入项目需要的各种标准库和第三方库
|
|
|
|
|
import datetime #zqx: 导入datetime模块,用于处理日期时间相关操作
|
|
|
|
|
import itertools #zqx: 导入itertools模块,用于高效的循环迭代操作
|
|
|
|
|
import json #zqx: 导入json模块,用于处理JSON数据格式
|
|
|
|
|
import logging #zqx: 导入logging模块,用于记录日志信息
|
|
|
|
|
from datetime import timezone #zqx: 从datetime模块导入timezone,用于处理时区相关操作
|
|
|
|
|
from itertools import groupby #zqx: 从itertools模块导入groupby,用于对数据进行分组操作
|
|
|
|
|
|
|
|
|
|
import django #zqx: 导入django模块
|
|
|
|
|
import requests #zqx: 导入requests库,用于发送HTTP请求
|
|
|
|
|
# 导入Django的装饰器、HTTP响应类和视图相关模块 #zqx: 导入Django框架的各种视图相关组件
|
|
|
|
|
from django.contrib.auth.decorators import login_required #zqx: 从django.contrib.auth.decorators导入login_required装饰器,用于限制视图只能由登录用户访问
|
|
|
|
|
from django.http import HttpResponse #zqx: 从django.http导入HttpResponse,用于返回HTTP响应
|
|
|
|
|
from django.http import JsonResponse #zqx: 从django.http导入JsonResponse,用于返回JSON格式的HTTP响应
|
|
|
|
|
from django.shortcuts import render #zqx: 从django.shortcuts导入render函数,用于渲染模板
|
|
|
|
|
from django.views.decorators.csrf import csrf_exempt #zqx: 从django.views.decorators导入csrf_exempt装饰器,用于免除CSRF验证
|
|
|
|
|
|
|
|
|
|
# 导入当前应用的OwnTrackLog模型 #zqx: 从当前应用的models模块导入OwnTrackLog数据模型
|
|
|
|
|
from .models import OwnTrackLog
|
|
|
|
|
|
|
|
|
|
# 获取日志记录器实例 #zqx: 获取名为__name__的日志记录器实例
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
# 装饰器,免除CSRF验证,用于接收外部系统POST请求 #zqx: 使用@csrf_exempt装饰器,免除该视图函数的CSRF验证,允许外部系统POST请求
|
|
|
|
|
@csrf_exempt
|
|
|
|
|
def manage_owntrack_log(request): #zqx: 定义manage_owntrack_log视图函数,接收request参数
|
|
|
|
|
try: #zqx: 开始异常处理块
|
|
|
|
|
# 解析请求体中的JSON数据 #zqx: 解析HTTP请求体中的JSON数据
|
|
|
|
|
s = json.loads(request.read().decode('utf-8')) #zqx: 读取请求体内容并解码为utf-8,然后解析为JSON对象
|
|
|
|
|
tid = s['tid'] #zqx: 从JSON对象中获取tid字段值(用户标识)
|
|
|
|
|
lat = s['lat'] #zqx: 从JSON对象中获取lat字段值(纬度)
|
|
|
|
|
lon = s['lon'] #zqx: 从JSON对象中获取lon字段值(经度)
|
|
|
|
|
|
|
|
|
|
# 记录接收到的位置信息日志 #zqx: 记录接收到的位置信息到日志
|
|
|
|
|
logger.info( #zqx: 使用logger记录info级别的日志信息
|
|
|
|
|
'tid:{tid}.lat:{lat}.lon:{lon}'.format( #zqx: 格式化日志信息字符串
|
|
|
|
|
tid=tid, lat=lat, lon=lon)) #zqx: 填充格式化参数
|
|
|
|
|
# 验证必要字段是否存在 #zqx: 验证必需的字段是否存在且不为空
|
|
|
|
|
if tid and lat and lon: #zqx: 判断tid、lat、lon三个字段是否都存在且不为空
|
|
|
|
|
# 创建并保存位置记录 #zqx: 创建OwnTrackLog实例并保存位置记录
|
|
|
|
|
m = OwnTrackLog() #zqx: 创建OwnTrackLog模型实例
|
|
|
|
|
m.tid = tid #zqx: 设置实例的tid属性
|
|
|
|
|
m.lat = lat #zqx: 设置实例的lat属性
|
|
|
|
|
m.lon = lon #zqx: 设置实例的lon属性
|
|
|
|
|
m.save() #zqx: 保存实例到数据库
|
|
|
|
|
return HttpResponse('ok') #zqx: 返回'ok'字符串响应
|
|
|
|
|
else: #zqx: 如果必要字段不完整
|
|
|
|
|
return HttpResponse('data error') #zqx: 返回'data error'字符串响应
|
|
|
|
|
except Exception as e: #zqx: 捕获所有异常
|
|
|
|
|
# 记录错误日志并返回错误响应 #zqx: 记录错误日志并返回错误响应
|
|
|
|
|
logger.error(e) #zqx: 使用logger记录error级别的异常信息
|
|
|
|
|
return HttpResponse('error') #zqx: 返回'error'字符串响应
|
|
|
|
|
|
|
|
|
|
# 装饰器,要求用户登录才能访问 #zqx: 使用@login_required装饰器,限制该视图只能由登录用户访问
|
|
|
|
|
@login_required
|
|
|
|
|
def show_maps(request): #zqx: 定义show_maps视图函数,接收request参数
|
|
|
|
|
# 检查用户是否为超级用户 #zqx: 检查当前登录用户是否为超级用户
|
|
|
|
|
if request.user.is_superuser: #zqx: 判断请求用户是否为超级用户
|
|
|
|
|
# 设置默认日期为当前UTC日期 #zqx: 设置默认日期为当前UTC日期
|
|
|
|
|
defaultdate = str(datetime.datetime.now(timezone.utc).date()) #zqx: 获取当前UTC时间的日期部分并转换为字符串
|
|
|
|
|
# 从GET参数获取日期,如果没有则使用默认日期 #zqx: 从请求GET参数中获取date参数,如果没有则使用默认日期
|
|
|
|
|
date = request.GET.get('date', defaultdate) #zqx: 获取GET参数中的date值,不存在时使用defaultdate
|
|
|
|
|
# 构造上下文数据 #zqx: 构造传递给模板的上下文数据
|
|
|
|
|
context = { #zqx: 定义context字典
|
|
|
|
|
'date': date #zqx: 将date变量添加到context字典中
|
|
|
|
|
}
|
|
|
|
|
# 渲染地图展示页面 #zqx: 渲染show_maps.html模板并返回响应
|
|
|
|
|
return render(request, 'owntracks/show_maps.html', context) #zqx: 使用render函数渲染模板并返回响应
|
|
|
|
|
else: #zqx: 如果用户不是超级用户
|
|
|
|
|
# 非超级用户返回403禁止访问 #zqx: 为非超级用户返回403禁止访问响应
|
|
|
|
|
from django.http import HttpResponseForbidden #zqx: 从django.http导入HttpResponseForbidden
|
|
|
|
|
return HttpResponseForbidden() #zqx: 返回403禁止访问响应
|
|
|
|
|
|
|
|
|
|
# 装饰器,要求用户登录才能访问 #zqx: 使用@login_required装饰器,限制该视图只能由登录用户访问
|
|
|
|
|
@login_required
|
|
|
|
|
def show_log_dates(request): #zqx: 定义show_log_dates视图函数,接收request参数
|
|
|
|
|
# 从数据库获取所有记录的创建时间 #zqx: 从数据库中查询OwnTrackLog模型的所有creation_time字段值
|
|
|
|
|
dates = OwnTrackLog.objects.values_list('creation_time', flat=True) #zqx: 使用values_list获取creation_time字段值,flat=True返回扁平化结果
|
|
|
|
|
# 提取日期部分并去重排序 #zqx: 提取日期部分,去重并排序
|
|
|
|
|
results = list(sorted(set(map(lambda x: x.strftime('%Y-%m-%d'), dates)))) #zqx: 使用map提取日期格式化字符串,set去重,sorted排序,list转换为列表
|
|
|
|
|
|
|
|
|
|
# 构造上下文数据 #zqx: 构造传递给模板的上下文数据
|
|
|
|
|
context = { #zqx: 定义context字典
|
|
|
|
|
'results': results #zqx: 将results变量添加到context字典中
|
|
|
|
|
}
|
|
|
|
|
# 渲染日期展示页面 #zqx: 渲染show_log_dates.html模板并返回响应
|
|
|
|
|
return render(request, 'owntracks/show_log_dates.html', context) #zqx: 使用render函数渲染模板并返回响应
|
|
|
|
|
|
|
|
|
|
# 将GPS坐标转换为高德地图坐标(批量处理,每次30个) #zqx: 定义convert_to_amap函数,用于将GPS坐标批量转换为高德地图坐标,每次处理30个点
|
|
|
|
|
def convert_to_amap(locations): #zqx: 定义convert_to_amap函数,接收locations参数(位置列表)
|
|
|
|
|
convert_result = [] #zqx: 初始化转换结果列表
|
|
|
|
|
# 创建迭代器 #zqx: 创建locations列表的迭代器
|
|
|
|
|
it = iter(locations) #zqx: 使用iter函数创建locations的迭代器
|
|
|
|
|
|
|
|
|
|
# 每次取30个位置点进行处理 #zqx: 每次从迭代器中取出30个位置点进行处理
|
|
|
|
|
item = list(itertools.islice(it, 30)) #zqx: 使用itertools.islice从迭代器中取出前30个元素
|
|
|
|
|
while item: #zqx: 当item列表不为空时循环处理
|
|
|
|
|
# 将经纬度格式化为高德API需要的格式 #zqx: 将经纬度数据格式化为高德API所需的格式
|
|
|
|
|
datas = ';'.join( #zqx: 使用';'连接符连接所有坐标字符串
|
|
|
|
|
set(map(lambda x: str(x.lon) + ',' + str(x.lat), item))) #zqx: 使用map提取每个位置的经度和纬度并格式化,set去重,join连接
|
|
|
|
|
|
|
|
|
|
# 高德地图API配置 #zqx: 配置高德地图坐标转换API的参数
|
|
|
|
|
key = '8440a376dfc9743d8924bf0ad141f28e' #zqx: 设置高德地图API的key
|
|
|
|
|
api = 'http://restapi.amap.com/v3/assistant/coordinate/convert' #zqx: 设置高德地图API的URL
|
|
|
|
|
query = { #zqx: 定义API请求参数字典
|
|
|
|
|
'key': key, #zqx: API密钥参数
|
|
|
|
|
'locations': datas, #zqx: 需要转换的坐标数据
|
|
|
|
|
'coordsys': 'gps' #zqx: 源坐标系为GPS
|
|
|
|
|
}
|
|
|
|
|
# 发送请求到高德API #zqx: 向高德地图API发送GET请求
|
|
|
|
|
rsp = requests.get(url=api, params=query) #zqx: 使用requests.get发送带参数的GET请求
|
|
|
|
|
result = json.loads(rsp.text) #zqx: 解析API响应的JSON数据
|
|
|
|
|
# 处理API响应结果 #zqx: 处理API返回的结果
|
|
|
|
|
if "locations" in result: #zqx: 判断响应结果中是否包含locations字段
|
|
|
|
|
convert_result.append(result['locations']) #zqx: 如果包含则将locations值添加到转换结果列表中
|
|
|
|
|
# 继续处理下一批数据 #zqx: 继续处理下一批30个数据
|
|
|
|
|
item = list(itertools.islice(it, 30)) #zqx: 从迭代器中继续取出下一批30个元素
|
|
|
|
|
|
|
|
|
|
# 返回转换后的坐标字符串 #zqx: 返回所有转换后的坐标字符串,用分号连接
|
|
|
|
|
return ";".join(convert_result) #zqx: 使用";"连接符连接所有转换结果并返回
|
|
|
|
|
|
|
|
|
|
# 装饰器,要求用户登录才能访问 #zqx: 使用@login_required装饰器,限制该视图只能由登录用户访问
|
|
|
|
|
@login_required
|
|
|
|
|
def get_datas(request): #zqx: 定义get_datas视图函数,接收request参数
|
|
|
|
|
# 获取当前UTC时间并设置为当天0点 #zqx: 获取当前UTC时间并设置为当天的0点0分0秒
|
|
|
|
|
now = django.utils.timezone.now().replace(tzinfo=timezone.utc) #zqx: 获取当前时间并设置时区为UTC
|
|
|
|
|
querydate = django.utils.timezone.datetime( #zqx: 创建查询开始日期时间对象
|
|
|
|
|
now.year, now.month, now.day, 0, 0, 0) #zqx: 设置为当年当月当日的0时0分0秒
|
|
|
|
|
# 如果GET参数中有指定日期,则使用指定日期 #zqx: 如果请求GET参数中包含date,则使用指定日期
|
|
|
|
|
if request.GET.get('date', None): #zqx: 判断GET参数中是否存在date参数
|
|
|
|
|
date = list(map(lambda x: int(x), request.GET.get('date').split('-'))) #zqx: 将date参数按'-'分割并转换为整数列表
|
|
|
|
|
querydate = django.utils.timezone.datetime( #zqx: 根据指定日期创建查询开始日期时间对象
|
|
|
|
|
date[0], date[1], date[2], 0, 0, 0) #zqx: 使用指定年月日创建datetime对象
|
|
|
|
|
# 计算查询结束时间(第二天0点) #zqx: 计算查询结束时间,为查询开始时间的下一天0点
|
|
|
|
|
nextdate = querydate + datetime.timedelta(days=1) #zqx: 查询结束时间为开始时间加上1天
|
|
|
|
|
# 查询指定日期范围内的位置记录 #zqx: 查询creation_time在指定日期范围内的OwnTrackLog记录
|
|
|
|
|
models = OwnTrackLog.objects.filter( #zqx: 使用filter方法筛选记录
|
|
|
|
|
creation_time__range=(querydate, nextdate)) #zqx: 筛选creation_time在querydate到nextdate范围内的记录
|
|
|
|
|
result = list() #zqx: 初始化结果列表
|
|
|
|
|
# 如果查询到数据,则按用户分组处理 #zqx: 如果查询到数据则按用户进行分组处理
|
|
|
|
|
if models and len(models): #zqx: 判断models是否存在且不为空
|
|
|
|
|
for tid, item in groupby( #zqx: 使用groupby按tid分组遍历models
|
|
|
|
|
sorted(models, key=lambda k: k.tid), key=lambda k: k.tid): #zqx: 先按tid排序,然后按tid分组
|
|
|
|
|
|
|
|
|
|
d = dict() #zqx: 创建字典对象存储用户轨迹数据
|
|
|
|
|
d["name"] = tid #zqx: 设置字典的name字段为用户标识tid
|
|
|
|
|
paths = list() #zqx: 初始化路径坐标列表
|
|
|
|
|
# 目前使用原始GPS坐标,注释掉的代码是使用高德转换坐标的部分 #zqx: 当前使用原始GPS坐标,注释掉的是高德坐标转换的代码
|
|
|
|
|
# locations = convert_to_amap( #zqx: 调用convert_to_amap函数转换坐标(已注释)
|
|
|
|
|
# sorted(item, key=lambda x: x.creation_time)) #zqx: 按创建时间排序后转换(已注释)
|
|
|
|
|
# for i in locations.split(';'): #zqx: 遍历转换后的坐标字符串(已注释)
|
|
|
|
|
# paths.append(i.split(',')) #zqx: 将坐标分割后添加到路径列表(已注释)
|
|
|
|
|
# 使用GPS原始经纬度按时间排序 #zqx: 使用原始GPS坐标按时间排序
|
|
|
|
|
for location in sorted(item, key=lambda x: x.creation_time): #zqx: 遍历分组后的记录并按创建时间排序
|
|
|
|
|
paths.append([str(location.lon), str(location.lat)]) #zqx: 将经度和纬度转换为字符串并添加到路径列表
|
|
|
|
|
d["path"] = paths #zqx: 设置字典的path字段为路径坐标列表
|
|
|
|
|
result.append(d) #zqx: 将用户轨迹数据字典添加到结果列表
|
|
|
|
|
# 返回JSON格式的轨迹数据 #zqx: 返回JSON格式的轨迹数据响应
|
|
|
|
|
return JsonResponse(result, safe=False) #zqx: 使用JsonResponse返回结果,safe=False允许非字典对象
|
|
|
|
|
|