def handle(self, *args, **options): """command handle function. retrieves tags by id """ try: from_tag_ids = parse_tag_ids(options['from']) to_tag_ids = parse_tag_ids(options['to']) except: raise CommandError('Tag IDs must be integer') in_both = from_tag_ids & to_tag_ids if in_both: tag_str = ', '.join([str(i) for i in in_both]) if len(in_both) > 1: error_message = 'Tags with IDs %s appear ' % tag_str else: error_message = 'Tag with ID %s appears ' % tag_str raise CommandError(error_message + 'in both --from and --to sets') from_tags = get_tags_by_ids(from_tag_ids) to_tags = get_tags_by_ids(to_tag_ids) admin = get_admin(options['user_id']) exercises = models.Thread.objects.all() for from_tag in from_tags: exercises = exercises.filter(tags=from_tag) #print some feedback here and give a chance to bail out exercise_count = exercises.count() if exercise_count == 0: print """Did not find any matching exercises, you might want to run prune_unused_tags or repost a bug, if that does not help""" elif exercise_count == 1: print "One exercise matches:" elif exercise_count <= 10: print "%d exercises match:" % exercise_count if exercise_count > 10: print "%d exercises match." % exercise_count print "First 10 are:" for exercise in exercises[:10]: print '* %s' % exercise.title.strip() from_tag_names = format_tag_name_list(from_tags) to_tag_names = format_tag_name_list(to_tags) prompt = 'Rename tags %s --> %s?' % (from_tag_names, to_tag_names) choice = console.choice_dialog(prompt, choices=('yes', 'no')) if choice == 'no': print 'Canceled' sys.exit() else: sys.stdout.write('Processing:') #actual processing stage, only after this point we start to #modify stuff in the database, one exercise per transaction from_tag_names = get_tag_names(from_tags) to_tag_names = get_tag_names(to_tags) i = 0 for exercise in exercises: tag_names = set(exercise.get_tag_names()) tag_names.update(to_tag_names) tag_names.difference_update(from_tag_names) admin.retag_exercise( exercise=exercise._exercise_post(), tags=u' '.join(tag_names), #silent = True #do we want to timestamp activity on exercise ) i += 1 sys.stdout.write('%6.2f%%' % (100 * float(i) / float(exercise_count))) sys.stdout.write('\b' * 7) sys.stdout.flush() sys.stdout.write('\n')
def handle(self, *args, **options): """command handle function. retrieves tags by id """ try: tag_ids = parse_tag_ids(options['tags']) except: raise CommandError('Tag IDs must be integer') from_tags = get_tags_by_ids(tag_ids) admin = get_admin(options['user_id']) question_list = models.Thread.objects.all() for from_tag in from_tags: questions = question_list.filter(tags=from_tag) #print some feedback here and give a chance to bail out question_count = questions.count() if question_count == 0: print """Did not find any matching questions.""" from_tag.delete() sys.stdout.write('Erased Tag %s\n' % from_tag.name) continue elif question_count == 1: print "One question matches:" elif question_count <= 10: print "%d questions match:" % question_count if question_count > 10: print "%d questions match." % question_count print "First 10 are:" for question in questions[:10]: print '* %s' % question.title.strip() prompt = 'Remove tags %s ?' % (from_tag.name) choice = console.choice_dialog(prompt, choices=('yes', 'no')) if choice == 'no': print 'Canceled' continue else: sys.stdout.write('Processing:') #actual processing stage, only after this point we start to #modify stuff in the database, one question per transaction from_tag_names = get_tag_names([from_tag]) i = 0 skip = 0 for question in questions: tag_names = set(question.get_tag_names()) orig = "%s" % tag_names # If it's the only tag, keep it if len(tag_names) == 1: skip += 1 continue tag_names.difference_update(from_tag_names) print "%s -> %s" % (orig, tag_names) admin.retag_question( question = question._question_post(), tags = u' '.join(tag_names), #silent = True #do we want to timestamp activity on question ) i += 1 sys.stdout.write('%6.2f%%' % (100*float(i)/float(question_count))) sys.stdout.write('\b'*7) sys.stdout.flush() sys.stdout.write('\n') #transaction.commit() if skip < 1: # delete Tag from database #from_tag.delete() sys.stdout.write('Erased Tag %s\n' % from_tag_names) else: sys.stdout.write('Skipped %d Questions\n' % skip)
def run_command(self, lang): """method that runs the actual command""" #go through tags and find character case duplicates and eliminate them translation.activate(lang) tagnames = models.Tag.objects.filter( language_code=lang ).values_list('name', flat=True) self.admin = get_admin() #1) first we go through all tags and #either fix or delete illegal tags found_count = 0 for name in tagnames: try: tag = models.Tag.objects.get( name=name, language_code=lang ) except models.Tag.DoesNotExist: #tag with this name was already deleted, #because it was an invalid duplicate version #of other valid tag continue fixed_name = get_valid_tag_name(tag) #if fixed name is empty after cleaning, delete the tag if fixed_name == '': print 'Deleting invalid tag: %s' % name tag.delete() found_count += 1 continue if fixed_name != name: print 'Renaming tag: %s -> %s' % (name, fixed_name) #if tag name changed, see if there is a duplicate #with the same name, in which case we re-assign questions #with the current tag to that other duplicate #then delete the current tag as no longer used if fixed_name != name: try: duplicate_tag = models.Tag.objects.get( name=fixed_name, language_code=lang ) except models.Tag.DoesNotExist: pass self.retag_threads([tag], duplicate_tag) tag.delete() found_count += 1 continue #if there are case variant dupes, we assign questions #from the case variants to the current tag and #delete the case variant tags dupes = models.Tag.objects.filter( name__iexact=fixed_name, language_code=lang ).exclude(pk=tag.id) dupes_count = dupes.count() if dupes_count: self.retag_threads(dupes, tag) dupes.delete() found_count += dupes_count if tag.name != fixed_name: tag.name = fixed_name tag.save() transaction.commit() #2) go through questions and fix tag records on each # and recalculate all the denormalised tag names on threads threads = models.Thread.objects.all() checked_count = 0 total_count = threads.count() print "Searching for questions with inconsistent copies of tag records:", for thread in threads: #make sure that denormalized tag set is the same as normalized #we just add both the tags together and try to apply them #to the question tags = thread.tags.all() denorm_tag_set = set(thread.get_tag_names()) norm_tag_set = set(thread.tags.values_list('name', flat=True)) if norm_tag_set != denorm_tag_set: denorm_tag_set.update(norm_tag_set) cleaned_tag_set = set( models.Tag.objects.filter( name__in=denorm_tag_set, language_code=lang ).values_list('name', flat=True) ) self.admin.retag_question( question=thread._question_post(), tags=' '.join(cleaned_tag_set) ) transaction.commit() checked_count += 1 console.print_progress(checked_count, total_count) console.print_progress(checked_count, total_count) if found_count: print '%d problem questions found, tag records restored' % found_count else: print 'Did not find any problems'
def handle(self, *args, **options): """command handle function. retrieves tags by id """ translation.activate(django_settings.LANGUAGE_CODE) try: from_tag_ids = parse_tag_ids(options['from']) to_tag_ids = parse_tag_ids(options['to']) except: raise CommandError('Tag IDs must be integer') in_both = from_tag_ids & to_tag_ids if in_both: tag_str = ', '.join([str(i) for i in in_both]) if len(in_both) > 1: error_message = 'Tags with IDs %s appear ' % tag_str else: error_message = 'Tag with ID %s appears ' % tag_str raise CommandError(error_message + 'in both --from and --to sets') from_tags = get_tags_by_ids(from_tag_ids) to_tags = get_tags_by_ids(to_tag_ids) admin = get_admin(options['user_id']) questions = models.Thread.objects.all() for from_tag in from_tags: questions = questions.filter(tags=from_tag) #print some feedback here and give a chance to bail out question_count = questions.count() if question_count == 0: print """Did not find any matching questions, you might want to run prune_unused_tags or repost a bug, if that does not help""" elif question_count == 1: print "One question matches:" elif question_count <= 10: print "%d questions match:" % question_count if question_count > 10: print "%d questions match." % question_count print "First 10 are:" for question in questions[:10]: print '* %s' % question.title.strip() formatted_from_tag_names = format_tag_name_list(from_tags) formatted_to_tag_names = format_tag_name_list(to_tags) if not options.get('is_force', False): prompt = 'Rename tags %s --> %s?' % (formatted_from_tag_names, formatted_to_tag_names) choice = console.choice_dialog(prompt, choices=('yes', 'no')) if choice == 'no': print 'Canceled' sys.exit() else: print 'Renaming tags %s --> %s' % (formatted_from_tag_names, formatted_to_tag_names) sys.stdout.write('Processing:') from_tag_names = get_tag_names(from_tags) to_tag_names = get_tag_names(to_tags) #if user provided tag1 as to_tag, and tagsynonym tag1->tag2 exists. for to_tag_name in to_tag_names: try: tag_synonym = models.TagSynonym.objects.get(source_tag_name = to_tag_name) raise CommandError(u'You gave %s as --to argument, but TagSynonym: %s -> %s exists, probably you want to provide %s as --to argument' % (to_tag_name, tag_synonym.source_tag_name, tag_synonym.target_tag_name, tag_synonym.target_tag_name)) except models.TagSynonym.DoesNotExist: pass #actual processing stage, only after this point we start to #modify stuff in the database, one question per transaction i = 0 for question in questions: tag_names = set(question.get_tag_names()) tag_names.update(to_tag_names) tag_names.difference_update(from_tag_names) admin.retag_question( question = question._question_post(), tags = u' '.join(tag_names), #silent = True #do we want to timestamp activity on question ) question.invalidate_cached_thread_content_fragment() i += 1 sys.stdout.write('%6.2f%%' % (100*float(i)/float(question_count))) sys.stdout.write('\b'*7) sys.stdout.flush() sys.stdout.write('\n') #transaction.commit() #may need to run assertions on that there are #print 'Searching for similar tags...', #leftover_questions = models.Thread.objects.filter( # icontains=from_tag.name # ) #if leftover_questions.count() > 0: # tag_strings = leftover_questions.values_list('tagnames', flat=True) # similar_tags = get_similar_tags_from_strings( # tag_strings, # from_tag.name # ) # print '%d found:' % len(similar_tags), # print '\n*'.join(sorted(list(similar_tags))) #else: # print "None found." #print "Done." #transaction.commit() # A user wants to rename tag2->tag3 and tagsynonym tag1->tag2 exists. # we want to update tagsynonym (tag1->tag2) to (tag1->tag3) for from_tag_name in from_tag_names: # we need db_index for target_tag_name as well for this models.TagSynonym.objects.filter(target_tag_name = from_tag_name).update(target_tag_name = to_tag_name)
def run_command(self, lang): """method that runs the actual command""" #go through tags and find character case duplicates and eliminate them translation.activate(lang) tagnames = models.Tag.objects.filter(language_code=lang).values_list( 'name', flat=True) self.admin = get_admin() #1) first we go through all tags and #either fix or delete illegal tags found_count = 0 for name in tagnames: try: tag = models.Tag.objects.get(name=name, language_code=lang) except models.Tag.DoesNotExist: #tag with this name was already deleted, #because it was an invalid duplicate version #of other valid tag continue fixed_name = get_valid_tag_name(tag) #if fixed name is empty after cleaning, delete the tag if fixed_name == '': print 'Deleting invalid tag: %s' % name tag.delete() found_count += 1 continue if fixed_name != name: print 'Renaming tag: %s -> %s' % (name, fixed_name) #if tag name changed, see if there is a duplicate #with the same name, in which case we re-assign questions #with the current tag to that other duplicate #then delete the current tag as no longer used if fixed_name != name: try: duplicate_tag = models.Tag.objects.get(name=fixed_name, language_code=lang) except models.Tag.DoesNotExist: pass self.retag_threads([tag], duplicate_tag) tag.delete() found_count += 1 continue #if there are case variant dupes, we assign questions #from the case variants to the current tag and #delete the case variant tags dupes = models.Tag.objects.filter( name__iexact=fixed_name, language_code=lang).exclude(pk=tag.id) dupes_count = dupes.count() if dupes_count: self.retag_threads(dupes, tag) dupes.delete() found_count += dupes_count if tag.name != fixed_name: tag.name = fixed_name tag.save() transaction.commit() #2) go through questions and fix tag records on each # and recalculate all the denormalised tag names on threads threads = models.Thread.objects.all() checked_count = 0 total_count = threads.count() print "Searching for questions with inconsistent copies of tag records:", for thread in threads: #make sure that denormalized tag set is the same as normalized #we just add both the tags together and try to apply them #to the question tags = thread.tags.all() denorm_tag_set = set(thread.get_tag_names()) norm_tag_set = set(thread.tags.values_list('name', flat=True)) if norm_tag_set != denorm_tag_set: denorm_tag_set.update(norm_tag_set) cleaned_tag_set = set( models.Tag.objects.filter(name__in=denorm_tag_set, language_code=lang).values_list( 'name', flat=True)) self.admin.retag_question(question=thread._question_post(), tags=' '.join(cleaned_tag_set)) transaction.commit() checked_count += 1 console.print_progress(checked_count, total_count) console.print_progress(checked_count, total_count) if found_count: print '%d problem questions found, tag records restored' % found_count else: print 'Did not find any problems'
def handle(self, *args, **options): """command handle function. reads tag names, decodes them using the standard input encoding and attempts to find the matching tags If "from" tag is not resolved, command fails if "to" tag is not resolved, a new tag is created """ if options['from'] is None: raise CommandError('the --from argument is required') if options['to'] is None: raise CommandError('the --to argument is required') source_tag_name = decode_input(options['from']) target_tag_name = decode_input(options['to']) if source_tag_name == target_tag_name: raise CommandError("source and target tags appear to be the same") admin = get_admin(seed_user_id=options['user_id']) source_tag = None is_source_tag_created = False try: source_tag = Tag.objects.get(name=source_tag_name, language_code=options['lang']) except Tag.DoesNotExist: if not options.get('is_force', False): prompt = """source tag %s doesn't exist, are you sure you want to create a TagSynonym %s ==> %s?""" % (source_tag_name, source_tag_name, target_tag_name) choice = console.choice_dialog(prompt, choices=('yes', 'no')) if choice == 'no': print('Cancled') sys.exit() source_tag = Tag.objects.create(name=source_tag_name, created_by=admin, language_code=options['lang']) is_source_tag_created = True # test if target_tag is actually synonym for yet another tag # when user asked tag2->tag3, we already had tag3->tag4. try: tag_synonym_tmp = TagSynonym.objects.get(source_tag_name=target_tag_name, language_code=options['lang']) if not options.get('is_force', False): prompt = """There exists a TagSynonym %s ==> %s, hence we will create a tag synonym %s ==> %s instead. Proceed?""" % ( tag_synonym_tmp.source_tag_name, tag_synonym_tmp.target_tag_name, source_tag_name, tag_synonym_tmp.target_tag_name) choice = console.choice_dialog(prompt, choices=('yes', 'no')) if choice == 'no': print('Cancled') sys.exit() target_tag_name = tag_synonym_tmp.target_tag_name options['to'] = target_tag_name except TagSynonym.DoesNotExist: pass try: Tag.objects.get(name=target_tag_name, language_code=options['lang']) except Tag.DoesNotExist: # we are creating a target tag, let's copy source tag's info # used_count are updated later Tag.objects.create(name=target_tag_name, created_by=admin, status=source_tag.status, tag_wiki=source_tag.tag_wiki, language_code=options['lang']) tag_synonym_tmp, created = TagSynonym.objects.get_or_create( source_tag_name=source_tag_name, target_tag_name=target_tag_name, owned_by=admin, language_code=options['lang']) management.call_command('rename_tags', *args, **options) # When source_tag_name is a target_tag_name of already existing TagSynonym. # ie. if tag1->tag2 exists when user asked tag2->tag3 # we are going to convert all tag1->tag2 to tag1->tag3 as well qs = TagSynonym.objects.filter(target_tag_name=source_tag_name, language_code=options['lang']) for existing_tag_synonym in qs: new_options = options.copy() new_options['from'] = existing_tag_synonym.source_tag_name new_options['user_id'] = admin.id new_options['is_force'] = True # this is mandatory conversion new_options['timestamp'] = timezone.now() existing_tag_synonym.delete() # no longer needed self.handle(*args, **new_options) # delete source Tag if is_source_tag_created: source_tag.delete() else: source_tag.deleted = True source_tag.deleted_at = options.get('timestamp', timezone.now()) source_tag.deleted_by = admin
def handle(self, *args, **options): """command handle function. reads tag names, decodes them using the standard input encoding and attempts to find the matching tags If "from" tag is not resolved, command fails if "to" tag is not resolved, a new tag is created """ if options['from'] is None: raise CommandError('the --from argument is required') if options['to'] is None: raise CommandError('the --to argument is required') source_tag_name = decode_input(options['from']) target_tag_name = decode_input(options['to']) if source_tag_name == target_tag_name: raise CommandError("source and target tags appear to be the same") admin = get_admin(seed_user_id=options['user_id']) source_tag = None is_source_tag_created = False try: source_tag = Tag.objects.get(name=source_tag_name, language_code=options['lang']) except Tag.DoesNotExist: if not options.get('is_force', False): prompt = """source tag %s doesn't exist, are you sure you want to create a TagSynonym %s ==> %s?""" % (source_tag_name, source_tag_name, target_tag_name) choice = console.choice_dialog(prompt, choices=('yes', 'no')) if choice == 'no': print('Cancled') sys.exit() source_tag = Tag.objects.create(name=source_tag_name, created_by=admin, language_code=options['lang']) is_source_tag_created = True # test if target_tag is actually synonym for yet another tag # when user asked tag2->tag3, we already had tag3->tag4. try: tag_synonym_tmp = TagSynonym.objects.get( source_tag_name=target_tag_name, language_code=options['lang']) if not options.get('is_force', False): prompt = """There exists a TagSynonym %s ==> %s, hence we will create a tag synonym %s ==> %s instead. Proceed?""" % ( tag_synonym_tmp.source_tag_name, tag_synonym_tmp.target_tag_name, source_tag_name, tag_synonym_tmp.target_tag_name) choice = console.choice_dialog(prompt, choices=('yes', 'no')) if choice == 'no': print('Cancled') sys.exit() target_tag_name = tag_synonym_tmp.target_tag_name options['to'] = target_tag_name except TagSynonym.DoesNotExist: pass try: Tag.objects.get(name=target_tag_name, language_code=options['lang']) except Tag.DoesNotExist: # we are creating a target tag, let's copy source tag's info # used_count are updated later Tag.objects.create(name=target_tag_name, created_by=admin, status=source_tag.status, tag_wiki=source_tag.tag_wiki, language_code=options['lang']) tag_synonym_tmp, created = TagSynonym.objects.get_or_create( source_tag_name=source_tag_name, target_tag_name=target_tag_name, owned_by=admin, language_code=options['lang']) management.call_command('rename_tags', *args, **options) # When source_tag_name is a target_tag_name of already existing TagSynonym. # ie. if tag1->tag2 exists when user asked tag2->tag3 # we are going to convert all tag1->tag2 to tag1->tag3 as well qs = TagSynonym.objects.filter(target_tag_name=source_tag_name, language_code=options['lang']) for existing_tag_synonym in qs: new_options = options.copy() new_options['from'] = existing_tag_synonym.source_tag_name new_options['user_id'] = admin.id new_options['is_force'] = True # this is mandatory conversion new_options['timestamp'] = timezone.now() existing_tag_synonym.delete() # no longer needed self.handle(*args, **new_options) # delete source Tag if is_source_tag_created: source_tag.delete() else: source_tag.deleted = True source_tag.deleted_at = options.get('timestamp', timezone.now()) source_tag.deleted_by = admin
def handle(self, *args, **options): """command handle function. retrieves tags by id """ translation.activate(django_settings.LANGUAGE_CODE) try: from_tag_ids = parse_tag_ids(options['from']) to_tag_ids = parse_tag_ids(options['to']) except: raise CommandError('Tag IDs must be integer') in_both = from_tag_ids & to_tag_ids if in_both: tag_str = ', '.join([str(i) for i in in_both]) if len(in_both) > 1: error_message = 'Tags with IDs %s appear ' % tag_str else: error_message = 'Tag with ID %s appears ' % tag_str raise CommandError(error_message + 'in both --from and --to sets') from_tags = get_tags_by_ids(from_tag_ids) to_tags = get_tags_by_ids(to_tag_ids) #all tags must belong to the same language lang_codes = set(tag.language_code for tag in (from_tags + to_tags)) if len(lang_codes) != 1: langs = ', '.join(lang_codes) raise CommandError( 'all tags must belong to the same language, have: %s' % langs) lang = list(lang_codes).pop() admin = get_admin(options['user_id']) questions = models.Thread.objects.all() for from_tag in from_tags: questions = questions.filter(tags=from_tag) #print some feedback here and give a chance to bail out question_count = questions.count() if question_count == 0: print("""Did not find any matching questions, you might want to run prune_unused_tags or repost a bug, if that does not help""") elif question_count == 1: print("One question matches:") elif question_count <= 10: print("%d questions match:" % question_count) if question_count > 10: print("%d questions match." % question_count) print("First 10 are:") for question in questions[:10]: print('* %s' % question.title.strip()) formatted_from_tag_names = format_tag_name_list(from_tags) formatted_to_tag_names = format_tag_name_list(to_tags) if not options.get('is_force', False): prompt = 'Rename tags %s --> %s?' % (formatted_from_tag_names, formatted_to_tag_names) choice = console.choice_dialog(prompt, choices=('yes', 'no')) if choice == 'no': print('Canceled') sys.exit() else: print('Renaming tags %s --> %s' % (formatted_from_tag_names, formatted_to_tag_names)) sys.stdout.write('Processing:') from_tag_names = get_tag_names(from_tags) to_tag_names = get_tag_names(to_tags) #if user provided tag1 as to_tag, and tagsynonym tag1->tag2 exists. for to_tag_name in to_tag_names: try: tag_synonym = models.TagSynonym.objects.get( source_tag_name=to_tag_name, language_code=lang) raise CommandError( u'You gave %s as --to argument, but TagSynonym: %s -> %s exists, probably you want to provide %s as --to argument' % (to_tag_name, tag_synonym.source_tag_name, tag_synonym.target_tag_name, tag_synonym.target_tag_name)) except models.TagSynonym.DoesNotExist: pass #actual processing stage, only after this point we start to #modify stuff in the database, one question per transaction i = 0 for question in questions: tag_names = set(question.get_tag_names()) tag_names.update(to_tag_names) tag_names.difference_update(from_tag_names) admin.retag_question( question=question._question_post(), tags=u' '.join(tag_names), #silent = True #do we want to timestamp activity on question ) question.invalidate_cached_summary_html() i += 1 sys.stdout.write('%6.2f%%' % (100 * float(i) / float(question_count))) sys.stdout.write('\b' * 7) sys.stdout.flush() sys.stdout.write('\n') #may need to run assertions on that there are #print 'Searching for similar tags...', #leftover_questions = models.Thread.objects.filter( # icontains=from_tag.name # ) #if leftover_questions.count() > 0: # tag_strings = leftover_questions.values_list('tagnames', flat=True) # similar_tags = get_similar_tags_from_strings( # tag_strings, # from_tag.name # ) # print '%d found:' % len(similar_tags), # print '\n*'.join(sorted(list(similar_tags))) #else: # print "None found." #print "Done." # A user wants to rename tag2->tag3 and tagsynonym tag1->tag2 exists. # we want to update tagsynonym (tag1->tag2) to (tag1->tag3) for from_tag_name in from_tag_names: # we need db_index for target_tag_name as well for this models.TagSynonym.objects.filter( target_tag_name=from_tag_name, language_code=lang).update(target_tag_name=to_tag_name)
def handle(self, *args, **options): """command handle function. retrieves tags by id """ try: from_tag_ids = parse_tag_ids(options['from']) to_tag_ids = parse_tag_ids(options['to']) except: raise CommandError('Tag IDs must be integer') in_both = from_tag_ids & to_tag_ids if in_both: tag_str = ', '.join([str(i) for i in in_both]) if len(in_both) > 1: error_message = 'Tags with IDs %s appear ' % tag_str else: error_message = 'Tag with ID %s appears ' % tag_str raise CommandError(error_message + 'in both --from and --to sets') from_tags = get_tags_by_ids(from_tag_ids) to_tags = get_tags_by_ids(to_tag_ids) admin = get_admin(options['user_id']) questions = models.Question.objects.all() for from_tag in from_tags: questions = questions.filter(tags = from_tag) #print some feedback here and give a chance to bail out question_count = questions.count() if question_count == 0: print """Did not find any matching questions, you might want to run prune_unused_tags or repost a bug, if that does not help""" elif question_count == 1: print "One question matches:" elif question_count <= 10: print "%d questions match:" % question_count if question_count > 10: print "%d questions match." % question_count print "First 10 are:" for question in questions[:10]: print '* %s' % question.thread.title.strip() from_tag_names = format_tag_name_list(from_tags) to_tag_names = format_tag_name_list(to_tags) prompt = 'Rename tags %s --> %s?' % (from_tag_names, to_tag_names) choice = console.choice_dialog(prompt, choices=('yes', 'no')) if choice == 'no': print 'Canceled' sys.exit() else: sys.stdout.write('Processing:') #actual processing stage, only after this point we start to #modify stuff in the database, one question per transaction from_tag_names = get_tag_names(from_tags) to_tag_names = get_tag_names(to_tags) i = 0 for question in questions: tag_names = set(question.get_tag_names()) tag_names.update(to_tag_names) tag_names.difference_update(from_tag_names) admin.retag_question( question = question, tags = u' '.join(tag_names), #silent = True #do we want to timestamp activity on question ) i += 1 sys.stdout.write('%6.2f%%' % (100*float(i)/float(question_count))) sys.stdout.write('\b'*7) sys.stdout.flush() sys.stdout.write('\n')
def handle(self, *args, **options): """command handle function. retrieves tags by id """ try: tag_ids = parse_tag_ids(options['tags']) except: raise CommandError('Tag IDs must be integer') from_tags = get_tags_by_ids(tag_ids) admin = get_admin(options['user_id']) question_list = models.Thread.objects.all() for from_tag in from_tags: questions = question_list.filter(tags=from_tag) #print some feedback here and give a chance to bail out question_count = questions.count() if question_count == 0: print """Did not find any matching questions.""" from_tag.delete() sys.stdout.write('Erased Tag %s\n' % from_tag.name) continue elif question_count == 1: print "One question matches:" elif question_count <= 10: print "%d questions match:" % question_count if question_count > 10: print "%d questions match." % question_count print "First 10 are:" for question in questions[:10]: print '* %s' % question.title.strip() prompt = 'Remove tags %s ?' % (from_tag.name) choice = console.choice_dialog(prompt, choices=('yes', 'no')) if choice == 'no': print 'Canceled' continue else: sys.stdout.write('Processing:') #actual processing stage, only after this point we start to #modify stuff in the database, one question per transaction from_tag_names = get_tag_names([from_tag]) i = 0 skip = 0 for question in questions: tag_names = set(question.get_tag_names()) orig = "%s" % tag_names # If it's the only tag, keep it if len(tag_names) == 1: skip += 1 continue tag_names.difference_update(from_tag_names) print "%s -> %s" % (orig, tag_names) admin.retag_question( question=question._question_post(), tags=u' '.join(tag_names), #silent = True #do we want to timestamp activity on question ) i += 1 sys.stdout.write('%6.2f%%' % (100 * float(i) / float(question_count))) sys.stdout.write('\b' * 7) sys.stdout.flush() sys.stdout.write('\n') #transaction.commit() if skip < 1: # delete Tag from database #from_tag.delete() sys.stdout.write('Erased Tag %s\n' % from_tag_names) else: sys.stdout.write('Skipped %d Questions\n' % skip)