diff --git a/show_checkin_data_sql.py b/show_checkin_data_sql.py new file mode 100644 index 0000000..2884db6 --- /dev/null +++ b/show_checkin_data_sql.py @@ -0,0 +1,248 @@ +#!/usr/bin/env python +""" +SQL直接実行版: 最近のGpsLogとCheckinImagesデータを表示 +Docker環境で動作 +""" + +import subprocess +import sys +import json +from datetime import datetime, timedelta + +def run_db_query(query): + """ + PostgreSQLクエリを実行 + """ + try: + cmd = [ + 'docker-compose', 'exec', '-T', 'db', + 'psql', '-U', 'admin', '-d', 'rogdb', + '-c', query + ] + + result = subprocess.run( + cmd, + capture_output=True, + text=True, + cwd='/Volumes/PortableSSD1TB/main/GifuTabi/rogaining_srv_exdb-2/rogaining_srv' + ) + + if result.returncode == 0: + return result.stdout + else: + print(f"❌ SQLエラー: {result.stderr}") + return None + + except Exception as e: + print(f"❌ 実行エラー: {e}") + return None + +def show_recent_gpslog(days=7): + """ + 最近のGpsLogデータを表示 + """ + print(f"\n📍 GpsLog (過去{days}日間)") + print("-" * 80) + + query = f""" + SELECT + id, + to_char(checkin_time, 'MM-DD HH24:MI:SS') as time, + zekken_number, + event_code, + cp_number, + CASE + WHEN image_address IS NOT NULL AND image_address != '' THEN '✅' + ELSE '❌' + END as has_image, + CASE + WHEN length(image_address) > 50 THEN left(image_address, 47) || '...' + ELSE coalesce(image_address, '') + END as image_preview + FROM rog_gpslog + WHERE checkin_time >= NOW() - INTERVAL '{days} days' + ORDER BY checkin_time DESC + LIMIT 20; + """ + + result = run_db_query(query) + if result: + print(result) + +def show_recent_checkinimages(days=7): + """ + 最近のCheckinImagesデータを表示 + """ + print(f"\n🖼️ CheckinImages (過去{days}日間)") + print("-" * 80) + + query = f""" + SELECT + ci.id, + to_char(ci.checkintime, 'MM-DD HH24:MI:SS') as time, + left(cu.email, 15) as user_email, + left(ci.team_name, 12) as team, + left(ci.event_code, 10) as event, + ci.cp_number, + CASE + WHEN ci.checkinimage IS NOT NULL AND ci.checkinimage != '' THEN '✅' + ELSE '❌' + END as has_file, + CASE + WHEN length(ci.checkinimage::text) > 30 THEN left(ci.checkinimage::text, 27) || '...' + ELSE coalesce(ci.checkinimage::text, '') + END as file_preview + FROM rog_checkinimages ci + LEFT JOIN auth_user cu ON ci.user_id = cu.id + WHERE ci.checkintime >= NOW() - INTERVAL '{days} days' + ORDER BY ci.checkintime DESC + LIMIT 20; + """ + + result = run_db_query(query) + if result: + print(result) + +def show_table_stats(): + """ + テーブル統計情報を表示 + """ + print(f"\n📊 テーブル統計") + print("-" * 50) + + query = """ + SELECT + 'GpsLog' as table_name, + count(*) as total_count, + count(CASE WHEN image_address IS NOT NULL AND image_address != '' THEN 1 END) as with_image, + to_char(min(checkin_time), 'YYYY-MM-DD') as oldest_date, + to_char(max(checkin_time), 'YYYY-MM-DD HH24:MI') as latest_date + FROM rog_gpslog + UNION ALL + SELECT + 'CheckinImages' as table_name, + count(*) as total_count, + count(CASE WHEN checkinimage IS NOT NULL AND checkinimage != '' THEN 1 END) as with_file, + to_char(min(checkintime), 'YYYY-MM-DD') as oldest_date, + to_char(max(checkintime), 'YYYY-MM-DD HH24:MI') as latest_date + FROM rog_checkinimages; + """ + + result = run_db_query(query) + if result: + print(result) + +def show_event_stats(): + """ + イベント別統計を表示 + """ + print(f"\n🎯 イベント別統計 (GpsLog)") + print("-" * 40) + + query = """ + SELECT + event_code, + count(*) as checkin_count, + count(CASE WHEN image_address IS NOT NULL AND image_address != '' THEN 1 END) as with_image_count, + to_char(min(checkin_time), 'MM-DD') as first_checkin, + to_char(max(checkin_time), 'MM-DD') as last_checkin + FROM rog_gpslog + GROUP BY event_code + ORDER BY checkin_count DESC + LIMIT 10; + """ + + result = run_db_query(query) + if result: + print(result) + + print(f"\n🖼️ イベント別統計 (CheckinImages)") + print("-" * 40) + + query = """ + SELECT + event_code, + count(*) as image_count, + count(DISTINCT team_name) as unique_teams, + to_char(min(checkintime), 'MM-DD') as first_image, + to_char(max(checkintime), 'MM-DD') as last_image + FROM rog_checkinimages + GROUP BY event_code + ORDER BY image_count DESC + LIMIT 10; + """ + + result = run_db_query(query) + if result: + print(result) + +def show_recent_activity(): + """ + 最近のアクティビティを時系列で表示 + """ + print(f"\n⏰ 最近のアクティビティ (時系列)") + print("-" * 60) + + query = """ + ( + SELECT + 'GpsLog' as source, + checkin_time as timestamp, + zekken_number as identifier, + event_code, + cp_number, + CASE WHEN image_address IS NOT NULL AND image_address != '' THEN 'with_image' ELSE 'no_image' END as note + FROM rog_gpslog + WHERE checkin_time >= NOW() - INTERVAL '24 hours' + ) + UNION ALL + ( + SELECT + 'CheckinImages' as source, + checkintime as timestamp, + team_name as identifier, + event_code, + cp_number::text, + 'image_upload' as note + FROM rog_checkinimages + WHERE checkintime >= NOW() - INTERVAL '24 hours' + ) + ORDER BY timestamp DESC + LIMIT 15; + """ + + result = run_db_query(query) + if result: + print(result) + +def main(): + """ + メイン関数 + """ + print("🏃‍♂️ ロゲイニング チェックインデータ表示ツール (SQL版)") + print("=" * 80) + + # 引数処理 + days = 7 + if len(sys.argv) > 1: + try: + days = int(sys.argv[1]) + except ValueError: + print("⚠️ 日数は数値で指定してください (デフォルト: 7日)") + days = 7 + + print(f"📅 過去{days}日間のデータを表示します") + + # データ表示 + show_recent_gpslog(days) + show_recent_checkinimages(days) + show_table_stats() + show_event_stats() + show_recent_activity() + + print(f"\n✅ 完了") + print(f"\n使用方法: python3 {sys.argv[0]} [日数]") + print(f"例: python3 {sys.argv[0]} 3 # 過去3日間のデータ") + +if __name__ == '__main__': + main() diff --git a/show_recent_checkin_data.py b/show_recent_checkin_data.py new file mode 100644 index 0000000..09426ae --- /dev/null +++ b/show_recent_checkin_data.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python +""" +最近のGpsLogとCheckinImagesデータを表示するスクリプト +""" + +import os +import sys +import django +from datetime import datetime, timedelta +from django.utils import timezone + +# Django設定 +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') +django.setup() + +from rog.models import GpsLog, CheckinImages, CustomUser +from django.db import connection + +def show_recent_data(days=7): + """ + 最近のチェックインデータを表示 + + Args: + days (int): 過去何日分のデータを表示するか + """ + # 基準日時を計算 + since_date = timezone.now() - timedelta(days=days) + + print(f"=== 過去{days}日間のチェックインデータ ===") + print(f"検索期間: {since_date.strftime('%Y-%m-%d %H:%M:%S')} 以降") + print("-" * 80) + + # GpsLogの最近のデータ + print("\n📍 GpsLog (チェックイン記録)") + print("-" * 50) + + recent_gpslogs = GpsLog.objects.filter( + checkin_time__gte=since_date + ).order_by('-checkin_time')[:20] + + if recent_gpslogs: + print(f"件数: {recent_gpslogs.count()}件") + print() + print("ID | 時刻 | ゼッケン | イベント | CP | 画像URL") + print("-" * 80) + + for log in recent_gpslogs: + image_status = "✅" if log.image_address else "❌" + image_url_preview = log.image_address[:40] + "..." if log.image_address and len(log.image_address) > 40 else log.image_address or "" + + print(f"{log.id:5d} | {log.checkin_time.strftime('%m-%d %H:%M:%S'):15s} | {log.zekken_number:8s} | {log.event_code:11s} | {log.cp_number:4s} | {image_status} {image_url_preview}") + else: + print("データなし") + + # CheckinImagesの最近のデータ + print(f"\n🖼️ CheckinImages (写真記録)") + print("-" * 50) + + recent_images = CheckinImages.objects.filter( + checkintime__gte=since_date + ).order_by('-checkintime')[:20] + + if recent_images: + print(f"件数: {recent_images.count()}件") + print() + print("ID | 時刻 | ユーザー | チーム名 | イベント | CP | 画像ファイル") + print("-" * 100) + + for img in recent_images: + user_name = img.user.email[:12] if img.user else "Unknown" + team_name = img.team_name[:12] if img.team_name else "" + event_code = img.event_code[:11] if img.event_code else "" + image_file = str(img.checkinimage)[:30] + "..." if len(str(img.checkinimage)) > 30 else str(img.checkinimage) + + print(f"{img.id:5d} | {img.checkintime.strftime('%m-%d %H:%M:%S'):15s} | {user_name:12s} | {team_name:12s} | {event_code:11s} | {img.cp_number:4d} | {image_file}") + else: + print("データなし") + +def show_summary_stats(): + """ + チェックインデータの統計情報を表示 + """ + print(f"\n📊 データベース統計") + print("-" * 50) + + # 各テーブルの総件数 + gpslog_total = GpsLog.objects.count() + checkinimages_total = CheckinImages.objects.count() + + print(f"GpsLog 総件数: {gpslog_total:,}") + print(f"CheckinImages 総件数: {checkinimages_total:,}") + + # 最新・最古のデータ + if gpslog_total > 0: + latest_gpslog = GpsLog.objects.order_by('-checkin_time').first() + oldest_gpslog = GpsLog.objects.order_by('checkin_time').first() + print(f"GpsLog 最新: {latest_gpslog.checkin_time.strftime('%Y-%m-%d %H:%M:%S') if latest_gpslog else 'N/A'}") + print(f"GpsLog 最古: {oldest_gpslog.checkin_time.strftime('%Y-%m-%d %H:%M:%S') if oldest_gpslog else 'N/A'}") + + if checkinimages_total > 0: + latest_image = CheckinImages.objects.order_by('-checkintime').first() + oldest_image = CheckinImages.objects.order_by('checkintime').first() + print(f"CheckinImages 最新: {latest_image.checkintime.strftime('%Y-%m-%d %H:%M:%S') if latest_image else 'N/A'}") + print(f"CheckinImages 最古: {oldest_image.checkintime.strftime('%Y-%m-%d %H:%M:%S') if oldest_image else 'N/A'}") + + # 画像有りのGpsLog件数 + gpslog_with_images = GpsLog.objects.exclude(image_address__isnull=True).exclude(image_address='').count() + print(f"画像付きGpsLog: {gpslog_with_images:,} / {gpslog_total:,} ({gpslog_with_images/gpslog_total*100:.1f}%)" if gpslog_total > 0 else "画像付きGpsLog: 0") + +def show_event_breakdown(): + """ + イベント別のチェックイン件数を表示 + """ + print(f"\n🎯 イベント別チェックイン件数") + print("-" * 50) + + # GpsLogのイベント別集計 + print("GpsLog:") + with connection.cursor() as cursor: + cursor.execute(""" + SELECT event_code, COUNT(*) as count + FROM rog_gpslog + GROUP BY event_code + ORDER BY count DESC + LIMIT 10 + """) + + for row in cursor.fetchall(): + print(f" {row[0]:15s}: {row[1]:,}件") + + # CheckinImagesのイベント別集計 + print("\nCheckinImages:") + with connection.cursor() as cursor: + cursor.execute(""" + SELECT event_code, COUNT(*) as count + FROM rog_checkinimages + GROUP BY event_code + ORDER BY count DESC + LIMIT 10 + """) + + for row in cursor.fetchall(): + print(f" {row[0]:15s}: {row[1]:,}件") + +def main(): + """ + メイン関数 + """ + print("🏃‍♂️ ロゲイニング チェックインデータ表示ツール") + print("=" * 80) + + try: + # 引数処理 + days = 7 + if len(sys.argv) > 1: + try: + days = int(sys.argv[1]) + except ValueError: + print("⚠️ 日数は数値で指定してください") + days = 7 + + # データ表示 + show_recent_data(days) + show_summary_stats() + show_event_breakdown() + + print(f"\n✅ 完了") + + except Exception as e: + print(f"❌ エラーが発生しました: {e}") + import traceback + traceback.print_exc() + +if __name__ == '__main__': + main()