migration repaire
This commit is contained in:
1 parent
c8d45dd07c
commit
56d8760613
11 files changed
+492
-5064
No files matched your search
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
"""Read-only diagnostics for the legacy mobile uniqueness migration."""
|
||||
import json
|
||||
from collections import defaultdict
|
||||
from importlib import import_module
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.db import connections
|
||||
|
||||
from apps.cuser.cuser_model import CUser
|
||||
from apps.customer.models import Customer
|
||||
|
||||
|
||||
canonical_mobile = import_module(
|
||||
'apps.customer.migrations.0008_customer_mobile_unique'
|
||||
).canonical_mobile
|
||||
|
||||
|
||||
def _duplicate_groups(model, alias, per_workspace=False):
|
||||
"""Use the migration's exact comparison, including country-prefix collisions."""
|
||||
groups = defaultdict(list)
|
||||
fields = ['pk', 'mobile'] + (['sys_ws_id'] if per_workspace else [])
|
||||
for row in model.objects.using(alias).order_by('pk').values(*fields).iterator():
|
||||
mobile = canonical_mobile(row['mobile'])
|
||||
if mobile is None:
|
||||
continue
|
||||
key = (row['sys_ws_id'], mobile) if per_workspace else (None, mobile)
|
||||
groups[key].append(row['pk'])
|
||||
return [
|
||||
{'workspace_id': workspace, 'canonical_mobile': mobile, 'record_ids': ids}
|
||||
for (workspace, mobile), ids in groups.items() if len(ids) > 1
|
||||
]
|
||||
|
||||
|
||||
def _related_counts(record, alias):
|
||||
"""Count direct foreign-key dependents without reading their private contents."""
|
||||
counts = {}
|
||||
for relation in record._meta.related_objects:
|
||||
if relation.one_to_many or relation.one_to_one:
|
||||
label = f'{relation.related_model._meta.label}.{relation.field.name}'
|
||||
counts[label] = relation.related_model._default_manager.using(alias).filter(
|
||||
**{relation.field.attname: record.pk}
|
||||
).count()
|
||||
return counts
|
||||
|
||||
|
||||
def _customer_details(ids, alias):
|
||||
rows = Customer.objects.using(alias).filter(pk__in=ids).select_related(
|
||||
'sys_ws', 'cuser_role__cuser', 'cuser_role__role_type'
|
||||
).order_by('pk')
|
||||
details = []
|
||||
for row in rows:
|
||||
role = row.cuser_role
|
||||
details.append({
|
||||
'id': row.pk, 'name_family': row.name_family,
|
||||
'mobile': row.mobile, 'canonical_mobile': canonical_mobile(row.mobile),
|
||||
'workspace_id': row.sys_ws_id, 'workspace_name': row.sys_ws.name,
|
||||
'panel_role': None if role is None else {
|
||||
'id': role.pk, 'user_id': role.cuser_id, 'workspace_id': role.sys_ws_id,
|
||||
'role': role.role_type.role_name_en, 'mobile': role.mobile,
|
||||
'user_mobile': role.cuser.mobile if role.cuser_id else None,
|
||||
'is_active': role.is_active, 'customer_panel': role.customer_panel,
|
||||
},
|
||||
'related_counts': _related_counts(row, alias),
|
||||
})
|
||||
return details
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Report legacy Customer/CUser mobile conflicts; never modify or delete records.'
|
||||
# Must work before migrations, without checking unrelated model declarations.
|
||||
requires_system_checks = []
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('--database', default='default')
|
||||
parser.add_argument('--customer-ids', nargs='+', type=int, default=[])
|
||||
|
||||
def handle(self, *args, **options):
|
||||
alias = options['database']
|
||||
if alias not in connections:
|
||||
raise CommandError(f'Unknown database alias: {alias}')
|
||||
customer_groups = _duplicate_groups(Customer, alias, per_workspace=True)
|
||||
user_groups = _duplicate_groups(CUser, alias)
|
||||
customer_ids = set(options['customer_ids'])
|
||||
customer_ids.update(pk for group in customer_groups for pk in group['record_ids'])
|
||||
user_ids = [pk for group in user_groups for pk in group['record_ids']]
|
||||
report = {
|
||||
'read_only': True, 'database': alias,
|
||||
'duplicate_group_count': len(customer_groups) + len(user_groups),
|
||||
'customer_duplicate_groups': customer_groups,
|
||||
'user_duplicate_groups': user_groups,
|
||||
'customers': _customer_details(customer_ids, alias),
|
||||
'missing_requested_customer_ids': sorted(customer_ids - set(
|
||||
Customer.objects.using(alias).filter(pk__in=customer_ids).values_list('pk', flat=True)
|
||||
)),
|
||||
'users': [dict(row, canonical_mobile=canonical_mobile(row['mobile'])) for row in
|
||||
CUser.objects.using(alias).filter(pk__in=user_ids).order_by('pk').values(
|
||||
'id', 'username', 'name_family', 'mobile', 'is_active'
|
||||
)],
|
||||
}
|
||||
self.stdout.write(json.dumps(report, ensure_ascii=False, indent=2))
|
||||
Reference in new issue
Block a user