From ff3bb9743f3628f19f9add4ba55821233f197a10 Mon Sep 17 00:00:00 2001 From: Adarnof Date: Wed, 18 Jan 2017 19:52:04 -0500 Subject: [PATCH] Enforce unique IDs and names for eveonline models (#657) Should help narrow down #656. Please report IntegrityErrors. --- eveonline/admin.py | 12 +- eveonline/migrations/0007_unique_id_name.py | 122 ++++++++++++++++++++ eveonline/models.py | 14 +-- 3 files changed, 140 insertions(+), 8 deletions(-) create mode 100644 eveonline/migrations/0007_unique_id_name.py diff --git a/eveonline/admin.py b/eveonline/admin.py index df59046f..21fa6ed5 100644 --- a/eveonline/admin.py +++ b/eveonline/admin.py @@ -13,7 +13,17 @@ admin.site.register(EveCorporationInfo) class EveApiKeyPairAdmin(admin.ModelAdmin): search_fields = ['api_id', 'user__username'] - list_display = ['api_id', 'user'] + list_display = ['api_id', 'user', 'characters'] + + @staticmethod + def characters(obj): + return ', '.join(sorted([c.character_name for c in EveCharacter.objects.filter(api_id=obj.api_id)])) + + def get_search_results(self, request, queryset, search_term): + queryset, use_distinct = super(EveApiKeyPairAdmin, self).get_search_results(request, queryset, search_term) + chars = EveCharacter.objects.filter(character_name__icontains=search_term) + queryset |= EveApiKeyPair.objects.filter(api_id__in=[char.api_id for char in chars if bool(char.api_id)]) + return queryset, use_distinct class EveCharacterAdmin(admin.ModelAdmin): diff --git a/eveonline/migrations/0007_unique_id_name.py b/eveonline/migrations/0007_unique_id_name.py new file mode 100644 index 00000000..6aa0b593 --- /dev/null +++ b/eveonline/migrations/0007_unique_id_name.py @@ -0,0 +1,122 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-01-18 13:20 +from __future__ import unicode_literals + +from django.db import migrations, models + + +def get_duplicates(items): + return set([item for item in items if items.count(item) > 1]) + + +def enforce_unique_characters(apps, schema_editor): + EveCharacter = apps.get_model('eveonline', 'EveCharacter') + + ids = [c.character_id for c in EveCharacter.objects.all()] + duplicates = get_duplicates(ids) + for c_id in duplicates: + dupes = EveCharacter.objects.filter(character_id=c_id) + dupes.exclude(pk=dupes[0].pk).delete() + + names = [c.character_name for c in EveCharacter.objects.all()] + duplicates = get_duplicates(names) + for name in duplicates: + dupes = EveCharacter.objects.filter(character_name=name) + dupes.exclude(pk=dupes[0].pk).delete() + + +def enforce_unique_corporations(apps, schema_editor): + EveCorporationInfo = apps.get_model('eveonline', 'EveCorporationInfo') + + ids = [c.corporation_id for c in EveCorporationInfo.objects.all()] + duplicates = get_duplicates(ids) + for c_id in duplicates: + dupes = EveCorporationInfo.objects.filter(corporation_id=c_id) + dupes.exclude(pk=dupes[0].pk).delete() + + names = [c.corporation_name for c in EveCorporationInfo.objects.all()] + duplicates = get_duplicates(names) + for name in duplicates: + dupes = EveCorporationInfo.objects.filter(character_name=name) + dupes.exclude(pk=dupes[0].pk).delete() + + +def enforce_unique_alliances(apps, schema_editor): + EveAllianceInfo = apps.get_model('eveonline', 'EveAllianceInfo') + EveCorporationInfo = apps.get_model('eveonline', 'EveCorporationInfo') + + ids = [a.alliance_id for a in EveAllianceInfo.objects.all()] + duplicates = get_duplicates(ids) + for a_id in duplicates: + dupes = EveAllianceInfo.objects.filter(alliance_id=a_id) + to_be_kept = dupes[0] + EveCorporationInfo.objects.filter(alliance__pk__in=[a.pk for a in dupes.exclude(pk=to_be_kept.pk)]).update( + alliance=to_be_kept.pk) + dupes.exclude(pk=to_be_kept.pk).delete() + + names = [a.alliance_name for a in EveAllianceInfo.objects.all()] + duplicates = get_duplicates(names) + for name in duplicates: + dupes = EveAllianceInfo.objects.filter(alliance_name=name) + to_be_kept = dupes[0] + EveCorporationInfo.objects.filter(alliance__in=[a.pk for a in dupes.exclude(pk=to_be_kept.pk)]).update( + alliance=to_be_kept.pk) + dupes.exclude(pk=to_be_kept.pk).delete() + + +def enforce_unique_apis(apps, schema_editor): + EveApiKeyPair = apps.get_model('eveonline', 'EveApiKeyPair') + + ids = [api.api_id for api in EveApiKeyPair.objects.all()] + duplicates = get_duplicates(ids) + for api_id in duplicates: + dupes = EveApiKeyPair.objects.filter(api_id=api_id) + dupes.exclude(pk=dupes[0].pk).delete() + + +class Migration(migrations.Migration): + dependencies = [ + ('eveonline', '0006_allow_null_evecharacter_alliance'), + ] + + operations = [ + migrations.RunPython(enforce_unique_characters, migrations.RunPython.noop), + migrations.RunPython(enforce_unique_corporations, migrations.RunPython.noop), + migrations.RunPython(enforce_unique_alliances, migrations.RunPython.noop), + migrations.RunPython(enforce_unique_apis, migrations.RunPython.noop), + migrations.AlterField( + model_name='evecharacter', + name='character_id', + field=models.CharField(max_length=254, unique=True), + ), + migrations.AlterField( + model_name='evecharacter', + name='character_name', + field=models.CharField(max_length=254, unique=True), + ), + migrations.AlterField( + model_name='evecorporationinfo', + name='corporation_id', + field=models.CharField(max_length=254, unique=True), + ), + migrations.AlterField( + model_name='evecorporationinfo', + name='corporation_name', + field=models.CharField(max_length=254, unique=True), + ), + migrations.AlterField( + model_name='eveallianceinfo', + name='alliance_id', + field=models.CharField(max_length=254, unique=True), + ), + migrations.AlterField( + model_name='eveallianceinfo', + name='alliance_name', + field=models.CharField(max_length=254, unique=True), + ), + migrations.AlterField( + model_name='eveapikeypair', + name='api_id', + field=models.CharField(max_length=254, unique=True), + ), + ] diff --git a/eveonline/models.py b/eveonline/models.py index 1ecd8a04..1632d5c4 100644 --- a/eveonline/models.py +++ b/eveonline/models.py @@ -6,8 +6,8 @@ from django.contrib.auth.models import User @python_2_unicode_compatible class EveCharacter(models.Model): - character_id = models.CharField(max_length=254) - character_name = models.CharField(max_length=254) + character_id = models.CharField(max_length=254, unique=True) + character_name = models.CharField(max_length=254, unique=True) corporation_id = models.CharField(max_length=254) corporation_name = models.CharField(max_length=254) corporation_ticker = models.CharField(max_length=254) @@ -22,7 +22,7 @@ class EveCharacter(models.Model): @python_2_unicode_compatible class EveApiKeyPair(models.Model): - api_id = models.CharField(max_length=254) + api_id = models.CharField(max_length=254, unique=True) api_key = models.CharField(max_length=254) user = models.ForeignKey(User, blank=True, null=True) sso_verified = models.BooleanField(default=False) @@ -33,8 +33,8 @@ class EveApiKeyPair(models.Model): @python_2_unicode_compatible class EveAllianceInfo(models.Model): - alliance_id = models.CharField(max_length=254) - alliance_name = models.CharField(max_length=254) + alliance_id = models.CharField(max_length=254, unique=True) + alliance_name = models.CharField(max_length=254, unique=True) alliance_ticker = models.CharField(max_length=254) executor_corp_id = models.CharField(max_length=254) is_blue = models.BooleanField(default=False) @@ -45,8 +45,8 @@ class EveAllianceInfo(models.Model): @python_2_unicode_compatible class EveCorporationInfo(models.Model): - corporation_id = models.CharField(max_length=254) - corporation_name = models.CharField(max_length=254) + corporation_id = models.CharField(max_length=254, unique=True) + corporation_name = models.CharField(max_length=254, unique=True) corporation_ticker = models.CharField(max_length=254) member_count = models.IntegerField() is_blue = models.BooleanField(default=False)