datav.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # @Time : 2023/10/14 15:49
  4. # @Author : Allen
  5. import datetime
  6. import json
  7. import re
  8. import time
  9. from django.db.models import Count, Sum, Q
  10. from django.db.models.functions import TruncMonth, TruncDay
  11. from django.utils import timezone
  12. from rest_framework.decorators import action
  13. from rest_framework.permissions import IsAuthenticated
  14. from rest_framework.viewsets import GenericViewSet
  15. from conf.env import DATABASE_USER, DATABASE_NAME
  16. from dvadmin.system.models import Users, LoginLog, FileList
  17. from dvadmin.system.views.login_log import LoginLogSerializer
  18. from dvadmin.utils.json_response import DetailResponse
  19. from django.db import connection
  20. from django.utils.timezone import now
  21. from django.db.models import Count
  22. from django.db.models.functions import TruncDate
  23. from dvadmin.utils.string_util import format_bytes
  24. def jx_timestamp():
  25. cur_time = datetime.datetime.now()
  26. a = datetime.datetime.strftime(cur_time, '%Y-%m-%d %H:%M:%S')
  27. timeStamp = int(time.mktime(time.strptime(a, "%Y-%m-%d %H:%M:%S")))
  28. timeArray = time.localtime(timeStamp)
  29. otherStyleTime = time.strftime("%Y-%m-%d %H:%M:%S", timeArray)
  30. return otherStyleTime
  31. class DataVViewSet(GenericViewSet):
  32. queryset = LoginLog.objects.all()
  33. serializer_class = LoginLogSerializer
  34. extra_filter_backends = []
  35. ordering_fields = ['create_datetime']
  36. @action(methods=["GET"], detail=False, permission_classes=[IsAuthenticated])
  37. def users_login_total(self, request):
  38. """
  39. 用户登录总数数据
  40. :param request:
  41. :return:
  42. """
  43. login_total = LoginLog.objects.all().count()
  44. return DetailResponse(data={"login_total": login_total}, msg="获取成功")
  45. @action(methods=["GET"], detail=False, permission_classes=[IsAuthenticated])
  46. def users_total(self, request):
  47. """
  48. 用户总数
  49. :param request:
  50. :return:
  51. """
  52. users_total = Users.objects.all().count()
  53. return DetailResponse(data={"users_total": users_total, }, msg="获取成功")
  54. @action(methods=["GET"], detail=False, permission_classes=[IsAuthenticated])
  55. def attachment_total(self, request):
  56. """
  57. 附件统计数据
  58. :param request:
  59. :return:
  60. """
  61. count = FileList.objects.all().count()
  62. if count != 0:
  63. data = FileList.objects.aggregate(sum_size=Sum('size'))
  64. else:
  65. data = {"sum_size": 0}
  66. return DetailResponse(data={"count": count, "occupy_space": format_bytes(data.get('sum_size') or 0)},
  67. msg="获取成功")
  68. @action(methods=["GET"], detail=False, permission_classes=[IsAuthenticated])
  69. def database_total(self, request):
  70. """
  71. 数据库统计数据
  72. :param request:
  73. :return:
  74. """
  75. count = len(connection.introspection.table_names())
  76. database_type = connection.settings_dict['ENGINE']
  77. sql = None
  78. if 'mysql' in database_type:
  79. sql = "SELECT SUM(data_length + index_length) AS size FROM information_schema.TABLES WHERE table_schema = DATABASE()"
  80. elif 'postgres' in database_type or 'psqlextra' in database_type:
  81. sql = """SELECT SUM(pg_total_relation_size(quote_ident(schemaname) || '.' || quote_ident(tablename))) AS size FROM pg_tables WHERE schemaname = current_schema();"""
  82. elif 'oracle' in database_type:
  83. sql = "SELECT SUM(bytes) AS size FROM user_segments"
  84. elif 'microsoft' in database_type:
  85. sql = "SELECT SUM(size) * 8 AS size FROM sys.database_files"
  86. else:
  87. space = 0
  88. if sql:
  89. with connection.cursor() as cursor:
  90. try:
  91. cursor.execute(sql)
  92. result = cursor.fetchone()
  93. space = result[0]
  94. except Exception as e:
  95. print(e)
  96. space = '无权限'
  97. return DetailResponse(data={"count": count, "space": format_bytes(space or 0)}, msg="获取成功")
  98. @action(methods=["GET"], detail=False, permission_classes=[IsAuthenticated])
  99. def registered_user(self, request):
  100. """
  101. 用户注册趋势
  102. :param request:
  103. :return:
  104. """
  105. today = datetime.datetime.today()
  106. seven_days_ago = today - datetime.timedelta(days=30)
  107. users = Users.objects.filter(date_joined__gte=seven_days_ago).annotate(day=TruncDay('date_joined')).values(
  108. 'day').annotate(count=Count('id'))
  109. result = []
  110. for i in range(30):
  111. date = (today - datetime.timedelta(days=i)).strftime('%Y-%m-%d')
  112. count = 0
  113. for user in users:
  114. if user['day'] == date:
  115. count = user['count']
  116. break
  117. result.append({'day': date, 'count': count})
  118. # users_last_month = Users.objects.filter(date_joined__gte=last_month).annotate(day=TruncDate('date_joined')).values('day').annotate(count=Count('id'))
  119. return DetailResponse(data={"registered_user_list": result}, msg="获取成功")
  120. @action(methods=["GET"], detail=False, permission_classes=[IsAuthenticated])
  121. def registered_user(self, request):
  122. """
  123. 用户注册趋势
  124. :param request:
  125. :return:
  126. """
  127. day = 30
  128. today = datetime.datetime.today()
  129. seven_days_ago = today - datetime.timedelta(days=day)
  130. users = Users.objects.filter(create_datetime__gte=seven_days_ago).annotate(
  131. day=TruncDay('create_datetime')).values(
  132. 'day').annotate(count=Count('id')).order_by('-day')
  133. result = []
  134. data_dict = {ele.get('day').strftime('%Y-%m-%d'): ele.get('count') for ele in users}
  135. for i in range(day):
  136. date = (today - datetime.timedelta(days=i)).strftime('%Y-%m-%d')
  137. result.append({'day': date, 'count': data_dict[date] if date in data_dict else 0})
  138. result = sorted(result, key=lambda x: x['day'])
  139. return DetailResponse(data={"registered_user_list": result}, msg="获取成功")
  140. @action(methods=["GET"], detail=False, permission_classes=[IsAuthenticated])
  141. def login_user(self, request):
  142. """
  143. 用户登录趋势
  144. :param request:
  145. :return:
  146. """
  147. day = 30
  148. today = datetime.datetime.today()
  149. seven_days_ago = today - datetime.timedelta(days=day)
  150. users = LoginLog.objects.filter(create_datetime__gte=seven_days_ago).annotate(
  151. day=TruncDay('create_datetime')).values(
  152. 'day').annotate(count=Count('id')).order_by('-day')
  153. result = []
  154. data_dict = {ele.get('day').strftime('%Y-%m-%d'): ele.get('count') for ele in users}
  155. for i in range(day):
  156. date = (today - datetime.timedelta(days=i)).strftime('%Y-%m-%d')
  157. result.append({'day': date, 'count': data_dict[date] if date in data_dict else 0})
  158. result = sorted(result, key=lambda x: x['day'])
  159. return DetailResponse(data={"login_user": result}, msg="获取成功")
  160. @action(methods=["GET"], detail=False, permission_classes=[IsAuthenticated])
  161. def users_active(self, request):
  162. """
  163. 用户新增活跃数据统计
  164. :param request:
  165. :return:
  166. """
  167. today = datetime.date.today()
  168. seven_days_ago = today - datetime.timedelta(days=6)
  169. thirty_days_ago = today - datetime.timedelta(days=29)
  170. today_users = Users.objects.filter(date_joined__date=today).count()
  171. today_logins = Users.objects.filter(last_login__date=today).count()
  172. three_days_users = Users.objects.filter(date_joined__gte=seven_days_ago).count()
  173. seven_days_users = Users.objects.filter(date_joined__gte=thirty_days_ago).count()
  174. seven_days_active = Users.objects.filter(last_login__gte=seven_days_ago).values('last_login').annotate(
  175. count=Count('id', distinct=True)).count()
  176. monthly_active = Users.objects.filter(last_login__gte=thirty_days_ago).values('last_login').annotate(
  177. count=Count('id', distinct=True)).count()
  178. data = {
  179. 'today_users': today_users,
  180. 'today_logins': today_logins,
  181. 'three_days': three_days_users,
  182. 'seven_days': seven_days_users,
  183. 'seven_days_active': seven_days_active,
  184. 'monthly_active': monthly_active
  185. }
  186. return DetailResponse(data=data, msg="获取成功")
  187. @action(methods=["GET"], detail=False, permission_classes=[IsAuthenticated])
  188. def login_region(self, request):
  189. """
  190. 登录用户区域分布
  191. :param request:
  192. :return:
  193. """
  194. CHINA_PROVINCES = [
  195. {'name': '北京', 'code': '110000'},
  196. {'name': '天津', 'code': '120000'},
  197. {'name': '河北省', 'code': '130000'},
  198. {'name': '山西省', 'code': '140000'},
  199. {'name': '内蒙古', 'code': '150000'},
  200. {'name': '辽宁省', 'code': '210000'},
  201. {'name': '吉林省', 'code': '220000'},
  202. {'name': '黑龙江省', 'code': '230000'},
  203. {'name': '上海', 'code': '310000'},
  204. {'name': '江苏省', 'code': '320000'},
  205. {'name': '浙江省', 'code': '330000'},
  206. {'name': '安徽省', 'code': '340000'},
  207. {'name': '福建省', 'code': '350000'},
  208. {'name': '江西省', 'code': '360000'},
  209. {'name': '山东省', 'code': '370000'},
  210. {'name': '河南省', 'code': '410000'},
  211. {'name': '湖北省', 'code': '420000'},
  212. {'name': '湖南省', 'code': '430000'},
  213. {'name': '广东省', 'code': '440000'},
  214. {'name': '广西', 'code': '450000'},
  215. {'name': '海南省', 'code': '460000'},
  216. {'name': '重庆', 'code': '500000'},
  217. {'name': '四川省', 'code': '510000'},
  218. {'name': '贵州省', 'code': '520000'},
  219. {'name': '云南省', 'code': '530000'},
  220. {'name': '西藏', 'code': '540000'},
  221. {'name': '陕西省', 'code': '610000'},
  222. {'name': '甘肃省', 'code': '620000'},
  223. {'name': '青海省', 'code': '630000'},
  224. {'name': '宁夏', 'code': '640000'},
  225. {'name': '新疆', 'code': '650000'},
  226. {'name': '台湾', 'code': '710000'},
  227. {'name': '香港', 'code': '810000'},
  228. {'name': '澳门', 'code': '820000'},
  229. {'name': '钓鱼岛', 'code': '900000'},
  230. {'name': '未知区域', 'code': '000000'},
  231. ]
  232. provinces = [x['name'] for x in CHINA_PROVINCES]
  233. day = 30
  234. today = datetime.datetime.today()
  235. seven_days_ago = today - datetime.timedelta(days=day)
  236. province_data = LoginLog.objects.filter(create_datetime__gte=seven_days_ago).values('province').annotate(
  237. count=Count('id')).order_by('-count')
  238. province_dict = {p: 0 for p in provinces}
  239. for ele in province_data:
  240. if ele.get('province') in province_dict:
  241. province_dict[ele.get('province')] += ele.get('count')
  242. else:
  243. province_dict['未知区域'] += ele.get('count')
  244. data = [{'region': key, 'count': val} for key, val in province_dict.items()]
  245. data = sorted(data, key=lambda x: x['count'], reverse=True)
  246. return DetailResponse(data=data, msg="获取成功")