# Generated by Django 6.0.3 on 2026-03-14 19:41 from datetime import datetime, timezone from django.db import migrations, models def populate_exp_date_from_custom_properties(apps, schema_editor): """Backfill exp_date from custom_properties['user_info']['exp_date'].""" M3UAccountProfile = apps.get_model('m3u', 'M3UAccountProfile') profiles_to_update = [] for profile in M3UAccountProfile.objects.filter( custom_properties__isnull=False, ).exclude(custom_properties={}): user_info = profile.custom_properties.get('user_info', {}) raw_exp = user_info.get('exp_date') if raw_exp is None: continue parsed = None try: if isinstance(raw_exp, (int, float)): parsed = datetime.fromtimestamp(float(raw_exp), tz=timezone.utc) elif isinstance(raw_exp, str): try: parsed = datetime.fromtimestamp(float(raw_exp), tz=timezone.utc) except ValueError: parsed = datetime.fromisoformat(raw_exp) except (ValueError, TypeError, OSError): pass if parsed is not None: profile.exp_date = parsed profiles_to_update.append(profile) if profiles_to_update: M3UAccountProfile.objects.bulk_update(profiles_to_update, ['exp_date'], batch_size=500) class Migration(migrations.Migration): dependencies = [ ('m3u', '0018_add_profile_custom_properties'), ] operations = [ migrations.AddField( model_name='m3uaccountprofile', name='exp_date', field=models.DateTimeField(blank=True, help_text='Account expiration date, auto-synced from custom_properties on save', null=True), ), migrations.RunPython( populate_exp_date_from_custom_properties, reverse_code=migrations.RunPython.noop, ), ]