You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Django/owntracks-tyx/views.py

209 lines
6.8 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#tyx
"""
owntracks 应用的视图函数
处理位置数据的接收、展示和查询
"""
import datetime
import itertools
import json
import logging
from datetime import timezone
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 .models import OwnTrackLog
# 获取当前模块的日志器
logger = logging.getLogger(__name__)
@csrf_exempt # 免除CSRF保护便于外部应用调用
def manage_owntrack_log(request):
"""
接收和处理 OwnTracks 客户端发送的位置数据
POST请求接收JSON格式的位置数据并存入数据库
"""
try:
# 解析请求体中的JSON数据
s = json.loads(request.read().decode('utf-8'))
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.tid = tid
m.lat = lat
m.lon = lon
m.save() # 保存到数据库
return HttpResponse('ok') # 返回成功响应
else:
return HttpResponse('data error') # 数据不完整
except Exception as e:
# 记录错误信息
logger.error(e)
return HttpResponse('error') # 返回错误响应
@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
}
# 渲染地图展示页面
return render(request, 'owntracks/show_maps.html', context)
else:
# 非超级用户返回403禁止访问
from django.http import HttpResponseForbidden
return HttpResponseForbidden()
@login_required
def show_log_dates(request):
"""
显示所有有位置记录的日期列表
用于在地图页面中选择特定日期查看轨迹
"""
# 获取所有记录的创建时间
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
}
# 渲染日期列表页面
return render(request, 'owntracks/show_log_dates.html', context)
def convert_to_amap(locations):
"""
将GPS坐标转换为高德地图坐标系统
由于GPS坐标系与高德地图不同需要进行坐标转换
Args:
locations: OwnTrackLog 对象列表,包含经纬度信息
Returns:
str: 转换后的坐标字符串,格式为"经度,纬度;经度,纬度;..."
"""
convert_result = []
it = iter(locations) # 创建迭代器
# 每次处理30个坐标高德API限制
item = list(itertools.islice(it, 30))
while item:
# 将坐标格式化为高德API要求的格式
datas = ';'.join(
set(map(lambda x: str(x.lon) + ',' + str(x.lat), item)))
# 高德地图API密钥实际使用中应放在配置文件中
key = '8440a376dfc9743d8924bf0ad141f28e'
api = 'http://restapi.amap.com/v3/assistant/coordinate/convert'
query = {
'key': key,
'locations': datas,
'coordsys': 'gps' # 指定源坐标系为GPS
}
# 调用高德坐标转换API
rsp = requests.get(url=api, params=query)
result = json.loads(rsp.text)
# 检查API响应是否包含转换结果
if "locations" in result:
convert_result.append(result['locations'])
# 获取下一批坐标
item = list(itertools.islice(it, 30))
# 合并所有转换结果
return ";".join(convert_result)
@login_required
def get_datas(request):
"""
提供位置数据的JSON API接口
返回指定日期的用户轨迹数据,用于在地图上绘制路径
Returns:
JsonResponse: 包含用户轨迹数据的JSON响应
"""
# 获取当前时间并设置为UTC时区
now = django.utils.timezone.now().replace(tzinfo=timezone.utc)
# 设置查询日期为今天零点
querydate = django.utils.timezone.datetime(
now.year, now.month, now.day, 0, 0, 0)
# 如果请求中指定了日期,使用指定日期
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)
# 查询指定日期范围内的所有位置记录
models = OwnTrackLog.objects.filter(
creation_time__range=(querydate, nextdate))
result = list() # 初始化结果列表
# 如果有数据,按用户分组处理
if models and len(models):
# 按用户ID分组每个用户的轨迹单独处理
for tid, item in groupby(
sorted(models, key=lambda k: k.tid), key=lambda k: k.tid):
d = dict() # 创建用户数据字典
d["name"] = tid # 设置用户名
paths = list() # 初始化路径点列表
# 选项1使用高德转换后的经纬度当前被注释
# locations = convert_to_amap(
# sorted(item, key=lambda x: x.creation_time))
# for i in locations.split(';'):
# paths.append(i.split(','))
# 选项2使用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) # 添加到结果列表
# 返回JSON格式的响应
return JsonResponse(result, safe=False) # safe=False允许非字典对象被序列化