Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Offer Tag Merging #899

Open
rtpg opened this issue Jun 23, 2024 · 2 comments
Open

Offer Tag Merging #899

rtpg opened this issue Jun 23, 2024 · 2 comments
Assignees

Comments

@rtpg
Copy link
Contributor

rtpg commented Jun 23, 2024

Basically there are times where you want to say "I have Tag A and Tag B, let's have only Tag A". This would involve rewriting any TagItems and friends that are using Tag B to instead point to Tag A (and at the very end probably delete Tag B?)

Ideas of what we could offer:

  • a Python function like tag_b.merge_into(tag_a) (this would make tag A the canonical one)
  • a Django management command that could be used to do this merging
  • Something in the Admin where we could click on a tag, then say to merge that tag into another one

I think there's gotta be some functions like "find django objects that refer to this object", given that the Django Admin lists related items on delete...

@rtpg
Copy link
Contributor Author

rtpg commented Jun 23, 2024

(#470 is related to this)

@Trafire
Copy link
Contributor

Trafire commented Jun 23, 2024

Was using this as a way to explore the library this morning, Maybe something like this would work?

Idea here is provide a base_name and either get or create a tag with that base name.

Find all existing case insensitive versions of that tag, and update the to use the one that matches base_name. Then delete all the other tags.

from taggit.models import Tag, TaggedItem


def update_vs_delete_tags(base_tag_name):
    """
    Identifies tags that are duplicates of the base_tag_name case insensitive value.
    
    Ignores any duplicate values.
        
    """
    duplicate_tags = Tag.objects.filter(name__iexact=base_tag_name).exclude(tag__name=base_tag_name)
    existing_items = set(TaggedItem.objects.filter(tag__name=base_tag_name).values_list("object_id", "content_type_id"))
    to_update = []
    tagged_items = TaggedItem.objects.filter(tag__in=duplicate_tags)
    for tagged_item in tagged_items:
        comparison = (tagged_item.object_id, tagged_item.content_type_id)
        if comparison not in existing_items:
            to_update.append(tagged_item.id)
        existing_items.add(comparison)
    return to_update


def merge_case_insensitive_tags(base_tag_name):
    to_update = update_vs_delete_tags(base_tag_name)
    base_tag, _ = Tag.objects.get_or_create(name=base_tag_name)
    TaggedItem.objects.filter(tag__in=to_update).update(
        tag_id=base_tag.id
    )
    # Remove All Tags that are now redundant
    Tag.objects.filter(name__iexact=base_tag_name).exclude(tag__name=base_tag_name).delete()
    

@guel-codes guel-codes self-assigned this Jun 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants