| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- from django.apps import apps
- from django.core.management.base import BaseCommand, CommandError
- from utilities.fields import NaturalOrderingField
- class Command(BaseCommand):
- help = "Recalculate natural ordering values for the specified models"
- def add_arguments(self, parser):
- parser.add_argument(
- 'args', metavar='app_label.ModelName', nargs='*',
- help='One or more specific models (each prefixed with its app_label) to renaturalize',
- )
- def _get_models(self, names):
- """
- Compile a list of models to be renaturalized. If no names are specified, all models which have one or more
- NaturalOrderingFields will be included.
- """
- models = []
- if names:
- # Collect all NaturalOrderingFields present on the specified models
- for name in names:
- try:
- app_label, model_name = name.split('.')
- except ValueError:
- raise CommandError(
- "Invalid format: {}. Models must be specified in the form app_label.ModelName.".format(name)
- )
- try:
- app_config = apps.get_app_config(app_label)
- except LookupError as e:
- raise CommandError(str(e))
- try:
- model = app_config.get_model(model_name)
- except LookupError:
- raise CommandError("Unknown model: {}.{}".format(app_label, model_name))
- fields = [
- field for field in model._meta.concrete_fields if type(field) is NaturalOrderingField
- ]
- if not fields:
- raise CommandError(
- "Invalid model: {}.{} does not employ natural ordering".format(app_label, model_name)
- )
- models.append(
- (model, fields)
- )
- else:
- # Find *all* models with NaturalOrderingFields
- for app_config in apps.get_app_configs():
- for model in app_config.models.values():
- fields = [
- field for field in model._meta.concrete_fields if type(field) is NaturalOrderingField
- ]
- if fields:
- models.append(
- (model, fields)
- )
- return models
- def handle(self, *args, **options):
- models = self._get_models(args)
- if options['verbosity']:
- self.stdout.write("Renaturalizing {} models.".format(len(models)))
- for model, fields in models:
- for field in fields:
- target_field = field.target_field
- naturalize = field.naturalize_function
- count = 0
- # Print the model and field name
- if options['verbosity']:
- self.stdout.write(
- "{}.{} ({})... ".format(model._meta.label, field.target_field, field.name),
- ending='\n' if options['verbosity'] >= 2 else ''
- )
- self.stdout.flush()
- # Find all unique values for the field
- queryset = model.objects.values_list(target_field, flat=True).order_by(target_field).distinct()
- for value in queryset:
- naturalized_value = naturalize(value, max_length=field.max_length)
- if options['verbosity'] >= 2:
- self.stdout.write(" {} -> {}".format(value, naturalized_value), ending='')
- self.stdout.flush()
- # Update each unique field value in bulk
- changed = model.objects.filter(name=value).update(**{field.name: naturalized_value})
- if options['verbosity'] >= 2:
- self.stdout.write(" ({})".format(changed))
- count += changed
- # Print the total count of alterations for the field
- if options['verbosity'] >= 2:
- self.stdout.write(self.style.SUCCESS("{} {} updated ({} unique values)".format(
- count, model._meta.verbose_name_plural, queryset.count()
- )))
- elif options['verbosity']:
- self.stdout.write(self.style.SUCCESS(str(count)))
- if options['verbosity']:
- self.stdout.write(self.style.SUCCESS("Done."))
|