|
|
|
|
@ -1,4 +1,4 @@
|
|
|
|
|
# Create your views here.
|
|
|
|
|
# 导入所需的模块和库。
|
|
|
|
|
import datetime
|
|
|
|
|
import itertools
|
|
|
|
|
import json
|
|
|
|
|
@ -8,120 +8,155 @@ from itertools import groupby
|
|
|
|
|
|
|
|
|
|
import django
|
|
|
|
|
import requests
|
|
|
|
|
from django.contrib.auth.decorators import login_required
|
|
|
|
|
from django.http import HttpResponse
|
|
|
|
|
from django.http import JsonResponse
|
|
|
|
|
from django.shortcuts import render
|
|
|
|
|
from django.views.decorators.csrf import csrf_exempt
|
|
|
|
|
from django.contrib.auth.decorators import login_required # 用于要求用户登录的装饰器。
|
|
|
|
|
from django.http import HttpResponse # 用于返回 HTTP 响应。
|
|
|
|
|
from django.http import JsonResponse # 用于返回 JSON 格式的 HTTP 响应。
|
|
|
|
|
from django.shortcuts import render # 用于渲染模板并返回 HTTP 响应。
|
|
|
|
|
from django.views.decorators.csrf import csrf_exempt # 用于豁免 CSRF 验证的装饰器。
|
|
|
|
|
|
|
|
|
|
from .models import OwnTrackLog
|
|
|
|
|
from .models import OwnTrackLog # 导入自定义的 OwnTrackLog 模型。
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
logger = logging.getLogger(__name__) # 获取当前模块的日志记录器。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 视图函数:处理位置跟踪数据的记录。
|
|
|
|
|
# 使用 @csrf_exempt 装饰器豁免 CSRF 验证,适用于 API 接口。
|
|
|
|
|
@csrf_exempt
|
|
|
|
|
def manage_owntrack_log(request):
|
|
|
|
|
try:
|
|
|
|
|
# 从请求体中读取并解码 JSON 数据。
|
|
|
|
|
s = json.loads(request.read().decode('utf-8'))
|
|
|
|
|
tid = s['tid']
|
|
|
|
|
lat = s['lat']
|
|
|
|
|
lon = s['lon']
|
|
|
|
|
tid = s['tid'] # 提取用户标识。
|
|
|
|
|
lat = s['lat'] # 提取纬度。
|
|
|
|
|
lon = s['lon'] # 提取经度。
|
|
|
|
|
|
|
|
|
|
# 记录接收到的数据到日志。
|
|
|
|
|
logger.info(
|
|
|
|
|
'tid:{tid}.lat:{lat}.lon:{lon}'.format(
|
|
|
|
|
tid=tid, lat=lat, lon=lon))
|
|
|
|
|
|
|
|
|
|
# 检查必需的字段是否存在且不为空。
|
|
|
|
|
if tid and lat and lon:
|
|
|
|
|
m = OwnTrackLog()
|
|
|
|
|
m = OwnTrackLog() # 创建一个新的 OwnTrackLog 实例。
|
|
|
|
|
m.tid = tid
|
|
|
|
|
m.lat = lat
|
|
|
|
|
m.lon = lon
|
|
|
|
|
m.save()
|
|
|
|
|
return HttpResponse('ok')
|
|
|
|
|
m.save() # 保存实例到数据库。
|
|
|
|
|
return HttpResponse('ok') # 返回成功响应。
|
|
|
|
|
else:
|
|
|
|
|
return HttpResponse('data error')
|
|
|
|
|
return HttpResponse('data error') # 返回数据错误响应。
|
|
|
|
|
except Exception as e:
|
|
|
|
|
# 记录任何异常到日志。
|
|
|
|
|
logger.error(e)
|
|
|
|
|
return HttpResponse('error')
|
|
|
|
|
return HttpResponse('error') # 返回一般错误响应。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 视图函数:展示地图视图。
|
|
|
|
|
# 使用 @login_required 装饰器确保用户已登录,同时检查用户是否为超级用户。
|
|
|
|
|
@login_required
|
|
|
|
|
def show_maps(request):
|
|
|
|
|
if request.user.is_superuser:
|
|
|
|
|
# 获取当前 UTC 时间的日期,作为默认日期。
|
|
|
|
|
defaultdate = str(datetime.datetime.now(timezone.utc).date())
|
|
|
|
|
# 从请求参数中获取日期,如果未提供则使用默认日期。
|
|
|
|
|
date = request.GET.get('date', defaultdate)
|
|
|
|
|
# 构建传递给模板的上下文,包含日期信息。
|
|
|
|
|
context = {
|
|
|
|
|
'date': date
|
|
|
|
|
}
|
|
|
|
|
# 渲染 'owntracks/show_maps.html' 模板,并传递上下文。
|
|
|
|
|
return render(request, 'owntracks/show_maps.html', context)
|
|
|
|
|
else:
|
|
|
|
|
# 如果用户不是超级用户,返回 403 Forbidden 响应。
|
|
|
|
|
from django.http import HttpResponseForbidden
|
|
|
|
|
return HttpResponseForbidden()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 视图函数:展示日志日期视图。
|
|
|
|
|
# 使用 @login_required 装饰器确保用户已登录。
|
|
|
|
|
@login_required
|
|
|
|
|
def show_log_dates(request):
|
|
|
|
|
# 从 OwnTrackLog 对象中获取所有创建时间,并提取日期部分。
|
|
|
|
|
dates = OwnTrackLog.objects.values_list('creation_time', flat=True)
|
|
|
|
|
# 对日期进行排序并去重,转换为 'YYYY-MM-DD' 格式的字符串列表。
|
|
|
|
|
results = list(sorted(set(map(lambda x: x.strftime('%Y-%m-%d'), dates))))
|
|
|
|
|
|
|
|
|
|
# 构建传递给模板的上下文,包含日期结果列表。
|
|
|
|
|
context = {
|
|
|
|
|
'results': results
|
|
|
|
|
}
|
|
|
|
|
# 渲染 'owntracks/show_log_dates.html' 模板,并传递上下文。
|
|
|
|
|
return render(request, 'owntracks/show_log_dates.html', context)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 函数:将 GPS 坐标转换为高德地图坐标。
|
|
|
|
|
# 该函数通过调用高德地图的坐标转换 API 实现坐标转换。
|
|
|
|
|
def convert_to_amap(locations):
|
|
|
|
|
convert_result = []
|
|
|
|
|
it = iter(locations)
|
|
|
|
|
convert_result = [] # 用于存储转换后的坐标结果。
|
|
|
|
|
it = iter(locations) # 创建一个迭代器以便分批处理位置数据。
|
|
|
|
|
|
|
|
|
|
item = list(itertools.islice(it, 30))
|
|
|
|
|
item = list(itertools.islice(it, 30)) # 每次处理最多 30 个位置。
|
|
|
|
|
while item:
|
|
|
|
|
# 将位置数据拼接为 'lon,lat' 格式的字符串,使用分号分隔。
|
|
|
|
|
datas = ';'.join(
|
|
|
|
|
set(map(lambda x: str(x.lon) + ',' + str(x.lat), item)))
|
|
|
|
|
|
|
|
|
|
key = '8440a376dfc9743d8924bf0ad141f28e'
|
|
|
|
|
api = 'http://restapi.amap.com/v3/assistant/coordinate/convert'
|
|
|
|
|
key = '8440a376dfc9743d8924bf0ad141f28e' # 高德地图 API 的密钥,请根据实际情况替换。
|
|
|
|
|
api = 'http://restapi.amap.com/v3/assistant/coordinate/convert' # 高德地图坐标转换 API 的 URL。
|
|
|
|
|
query = {
|
|
|
|
|
'key': key,
|
|
|
|
|
'locations': datas,
|
|
|
|
|
'coordsys': 'gps'
|
|
|
|
|
'coordsys': 'gps' # 指定坐标系统为 GPS。
|
|
|
|
|
}
|
|
|
|
|
rsp = requests.get(url=api, params=query)
|
|
|
|
|
result = json.loads(rsp.text)
|
|
|
|
|
rsp = requests.get(url=api, params=query) # 发送 GET 请求到高德地图 API。
|
|
|
|
|
result = json.loads(rsp.text) # 解析 API 响应的 JSON 数据。
|
|
|
|
|
if "locations" in result:
|
|
|
|
|
# 如果响应中包含转换后的坐标,将其添加到结果列表中。
|
|
|
|
|
convert_result.append(result['locations'])
|
|
|
|
|
item = list(itertools.islice(it, 30))
|
|
|
|
|
item = list(itertools.islice(it, 30)) # 处理下一批 30 个位置。
|
|
|
|
|
|
|
|
|
|
# 将所有转换后的坐标结果拼接为一个字符串,使用分号分隔。
|
|
|
|
|
return ";".join(convert_result)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
|
# 视图函数:获取数据视图。
|
|
|
|
|
# 该视图根据请求参数获取特定日期范围内的轨迹数据,并返回 JSON 格式的响应。
|
|
|
|
|
def get_datas(request):
|
|
|
|
|
now = django.utils.timezone.now().replace(tzinfo=timezone.utc)
|
|
|
|
|
now = django.utils.timezone.now().replace(tzinfo=timezone.utc) # 获取当前的 UTC 时间。
|
|
|
|
|
querydate = django.utils.timezone.datetime(
|
|
|
|
|
now.year, now.month, now.day, 0, 0, 0)
|
|
|
|
|
now.year, now.month, now.day, 0, 0, 0) # 构建当天的起始时间(00:00:00)。
|
|
|
|
|
# 如果请求中包含日期参数,则根据参数构建查询日期。
|
|
|
|
|
if request.GET.get('date', None):
|
|
|
|
|
date = list(map(lambda x: int(x), request.GET.get('date').split('-')))
|
|
|
|
|
querydate = django.utils.timezone.datetime(
|
|
|
|
|
date[0], date[1], date[2], 0, 0, 0)
|
|
|
|
|
nextdate = querydate + datetime.timedelta(days=1)
|
|
|
|
|
nextdate = querydate + datetime.timedelta(days=1) # 计算查询日期的下一天,作为结束时间。
|
|
|
|
|
|
|
|
|
|
# 从 OwnTrackLog 对象中筛选出创建时间在查询日期范围内的数据。
|
|
|
|
|
models = OwnTrackLog.objects.filter(
|
|
|
|
|
creation_time__range=(querydate, nextdate))
|
|
|
|
|
result = list()
|
|
|
|
|
result = list() # 用于存储最终的结果数据。
|
|
|
|
|
if models and len(models):
|
|
|
|
|
# 按用户标识 (tid) 对数据进行分组和排序。
|
|
|
|
|
for tid, item in groupby(
|
|
|
|
|
sorted(models, key=lambda k: k.tid), key=lambda k: k.tid):
|
|
|
|
|
|
|
|
|
|
d = dict()
|
|
|
|
|
d["name"] = tid
|
|
|
|
|
paths = list()
|
|
|
|
|
# 使用高德转换后的经纬度
|
|
|
|
|
d = dict() # 创建一个字典,用于存储单个用户的数据。
|
|
|
|
|
d["name"] = tid # 用户标识。
|
|
|
|
|
paths = list() # 用于存储用户的轨迹路径。
|
|
|
|
|
# 目前代码中提供了使用高德转换后的经纬度和直接使用 GPS 原始经纬度的两种方式,
|
|
|
|
|
# 其中使用高德转换坐标的部分被注释。
|
|
|
|
|
|
|
|
|
|
# 使用高德转换后的经纬度(被注释)。
|
|
|
|
|
# locations = convert_to_amap(
|
|
|
|
|
# sorted(item, key=lambda x: x.creation_time))
|
|
|
|
|
# for i in locations.split(';'):
|
|
|
|
|
# paths.append(i.split(','))
|
|
|
|
|
# 使用GPS原始经纬度
|
|
|
|
|
|
|
|
|
|
# 使用 GPS 原始经纬度。
|
|
|
|
|
for location in sorted(item, key=lambda x: x.creation_time):
|
|
|
|
|
paths.append([str(location.lon), str(location.lat)])
|
|
|
|
|
d["path"] = paths
|
|
|
|
|
result.append(d)
|
|
|
|
|
return JsonResponse(result, safe=False)
|
|
|
|
|
paths.append([str(location.lon), str(location.lat)]) # 添加经纬度到路径列表。
|
|
|
|
|
d["path"] = paths # 将路径列表添加到用户数据字典中。
|
|
|
|
|
result.append(d) # 将用户数据字典添加到结果列表中。
|
|
|
|
|
# 将结果以 JSON 格式返回,设置 safe=False 以允许非字典类型的对象被序列化。
|
|
|
|
|
return JsonResponse(result, safe=False)
|