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.
DjangoBlog/views.py

162 lines
13 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.

# 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允许非字典对象