Files
rogaining_srv/complete_location2025_migration.py

207 lines
8.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
Location2025完全移行プログラム
7,641件の未移行ロケーションデータをLocation2025テーブルに移行
"""
import os
import sys
from datetime import datetime
# Django設定の初期化
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
sys.path.append('/opt/app')
try:
import django
django.setup()
from django.contrib.gis.geos import Point
from django.db import models
from rog.models import Location, Location2025, NewEvent2
except ImportError as e:
print(f"Django import error: {e}")
print("このスクリプトはDjangoコンテナ内で実行してください")
sys.exit(1)
def migrate_location_to_location2025():
"""Location から Location2025 への完全移行"""
print("=== Location2025完全移行開始 ===")
try:
# 現在の状況確認
total_location = Location.objects.count()
current_location2025 = Location2025.objects.count()
remaining = total_location - current_location2025
print(f"移行対象: {remaining}件 (全{total_location}件中{current_location2025}件移行済み)")
if remaining <= 0:
print("✅ すべてのLocationデータが既にLocation2025に移行済みです")
return True
# イベント確認(高山2以外の処理)
locations_by_event = Location.objects.values('event_name').annotate(
count=models.Count('id')
).order_by('-count')
print("イベント別未移行データ:")
for event_data in locations_by_event:
event_name = event_data['event_name']
count = event_data['count']
# 既に移行済みのデータ数確認
try:
event = NewEvent2.objects.get(event_code=event_name)
migrated = Location2025.objects.filter(event_id=event.id).count()
remaining_for_event = count - migrated
print(f" {event_name}: {remaining_for_event}件未移行 (全{count}件)")
except NewEvent2.DoesNotExist:
print(f" {event_name}: NewEvent2未登録のため移行不可 ({count}件)")
# バッチ移行処理
batch_size = 100
total_migrated = 0
# 高山イベントのLocationデータを取得
takayama_locations = Location.objects.filter(event_name='高山2')
if takayama_locations.exists():
# 高山のNewEvent2エントリを取得または作成
try:
takayama_event = NewEvent2.objects.filter(event_code='高山2').first()
if not takayama_event:
print("⚠️ 高山イベントをNewEvent2に作成中...")
takayama_event = NewEvent2.objects.create(
event_code='高山2',
event_name='岐阜ロゲin高山',
event_date=datetime(2025, 2, 11).date(),
start_time=datetime(2025, 2, 11, 10, 0).time(),
goal_time=datetime(2025, 2, 11, 15, 0).time(),
explanation='移行により自動作成されたイベント'
)
print(f"✅ 高山2イベント作成完了 (ID: {takayama_event.id})")
else:
print(f"✅ 高山2イベント (ID: {takayama_event.id}) 使用")
except Exception as e:
print(f"❌ 高山2イベント処理エラー: {e}")
return False
# 既存のLocation2025データと重複チェック
existing_location2025_ids = set(
Location2025.objects.filter(event_id=takayama_event.id).values_list('original_location_id', flat=True)
)
# 未移行のLocationデータを取得
pending_locations = takayama_locations.exclude(id__in=existing_location2025_ids)
pending_count = pending_locations.count()
print(f"高山2イベント: {pending_count}件の未移行データを処理中...")
# バッチ処理でLocation2025に移行
for i in range(0, pending_count, batch_size):
batch_locations = list(pending_locations[i:i+batch_size])
location2025_objects = []
for location in batch_locations:
# PostGIS Pointオブジェクト作成
point_geom = Point(float(location.longitude), float(location.latitude))
location2025_obj = Location2025(
cp_number=location.cp_number,
point=point_geom,
score=location.score,
event_id=takayama_event.id,
original_location_id=location.id,
create_time=location.create_time or datetime.now(),
update_time=datetime.now()
)
location2025_objects.append(location2025_obj)
# 一括挿入
Location2025.objects.bulk_create(location2025_objects, ignore_conflicts=True)
total_migrated += len(location2025_objects)
print(f"移行進捗: {total_migrated}/{pending_count}件完了")
# 移行結果確認
final_location2025_count = Location2025.objects.count()
print(f"\n✅ 移行完了: Location2025テーブルに{final_location2025_count}件のデータ")
print(f"今回移行: {total_migrated}")
# API互換性確認
print("\n=== API互換性確認 ===")
test_checkpoints = Location2025.objects.filter(
event_id=takayama_event.id
)[:5]
if test_checkpoints.exists():
print("✅ get_checkpoint_list API用サンプルデータ:")
for cp in test_checkpoints:
print(f" CP{cp.cp_number}: ({cp.point.x}, {cp.point.y}) - {cp.score}")
return True
except Exception as e:
print(f"❌ 移行エラー: {e}")
return False
def verify_migration_results():
"""移行結果の検証"""
print("\n=== 移行結果検証 ===")
try:
# データ数確認
location_count = Location.objects.count()
location2025_count = Location2025.objects.count()
print(f"Location (旧): {location_count}")
print(f"Location2025 (新): {location2025_count}")
if location2025_count >= location_count:
print("✅ 完全移行成功")
else:
remaining = location_count - location2025_count
print(f"⚠️ {remaining}件が未移行")
# イベント別確認
events_with_data = Location2025.objects.values('event_id').annotate(
count=models.Count('id')
)
print("\nLocation2025イベント別データ数:")
for event_data in events_with_data:
try:
event = NewEvent2.objects.get(id=event_data['event_id'])
print(f" {event.event_code}: {event_data['count']}")
except NewEvent2.DoesNotExist:
print(f" イベントID {event_data['event_id']}: {event_data['count']}件 (イベント情報なし)")
return True
except Exception as e:
print(f"❌ 検証エラー: {e}")
return False
def main():
"""メイン処理"""
print("=== Location2025完全移行プログラム ===")
print("目標: 残り7,641件のLocationデータをLocation2025に移行")
# 移行実行
success = migrate_location_to_location2025()
if success:
# 結果検証
verify_migration_results()
print("\n🎉 Location2025移行プログラム完了")
else:
print("\n❌ 移行に失敗しました")
return 1
return 0
if __name__ == "__main__":
exit(main())