gnm_deliverables/management/commands/merge_project_bundles.py (38 lines of code) (raw):
from django.core.management.base import BaseCommand
from gnm_deliverables.models import Deliverable, DeliverableAsset
import logging
logger = logging.getLogger(__name__)
class Command(BaseCommand):
"""
management command that will find multiple entries for a single project and coalesce them down to 1
"""
def distinct_project_ids(self):
"""
obtains all of the unique project id values
:return: a list of dict entries in the form `{"pluto_core_project_id": {numeric-id}}`
"""
return list(Deliverable.objects.order_by().values("pluto_core_project_id").distinct())
def merge_bundles(self, pluto_project_id):
"""
try to merge up all the bundles for the given project id
:param pluto_project_id:
:return:
"""
affected_bundles = list(Deliverable.objects.filter(pluto_core_project_id=pluto_project_id)) #convert generator to list immediately
start_asset_count = DeliverableAsset.objects.filter(deliverable__in=affected_bundles).count()
logger.info("There are {} assets affected by this move".format(start_asset_count))
merge_target:Deliverable = affected_bundles[0]
merge_sources:list= affected_bundles[1:]
merge_source_titles = [b.name for b in merge_sources]
logger.info("Merging bundles {0} onto bundle {1}".format(merge_source_titles, merge_target.name))
for merge_source in merge_sources:
source_bundle_assets = DeliverableAsset.objects.filter(deliverable=merge_source)
logger.info("\tBundle {0} has {1} deliverables to move".format(merge_source.name, len(source_bundle_assets)))
for asset in source_bundle_assets:
asset.deliverable = merge_target
asset.save()
#double-check that data has moved
remaining_assets_count = DeliverableAsset.objects.filter(deliverable=merge_source).count()
if remaining_assets_count>0:
raise RuntimeError("we thought we had moved everything for {0} {1} but there were {2} assets remaining!".format(merge_source.pk, merge_source.name, remaining_assets_count))
merge_source.delete()
final_asset_count = DeliverableAsset.objects.filter(deliverable=merge_target).count()
if final_asset_count != start_asset_count:
logger.error("We had {} assets to start with and {} at the end! something went wrong.".format(start_asset_count, final_asset_count))
raise RuntimeError("asset count mismatch")
logger.info("Finished processing {0}. New deliverable count is {1}".format(merge_target.name, final_asset_count))
def handle(self, *args, **opts):
all_known_project_ids = self.distinct_project_ids()
logger.info("A total of {0} project ids are registered with deliverable bundles".format(len(all_known_project_ids)))
for target_project_id in all_known_project_ids:
project_bundles_count = Deliverable.objects.filter(pluto_core_project_id=target_project_id["pluto_core_project_id"]).count()
logger.debug("Project id {} has {} associated bundles".format(target_project_id["pluto_core_project_id"], project_bundles_count))
if project_bundles_count>1:
self.merge_bundles(target_project_id["pluto_core_project_id"])