Skip to content

Commit

Permalink
Fix issue when merging tags when the item has both the old and new tag
Browse files Browse the repository at this point in the history
  • Loading branch information
rtpg committed Jul 26, 2024
1 parent 15ed6e5 commit c6c7bb2
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 5 deletions.
17 changes: 13 additions & 4 deletions taggit/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def get_urls(self):
path(
"merge-tags/",
self.admin_site.admin_view(self.merge_tags_view),
name="merge_tags",
name="taggit_tag_merge_tags",
),
]
return custom_urls + urls
Expand Down Expand Up @@ -58,9 +58,18 @@ def merge_tags_view(self, request):
tag = Tag.objects.get(id=tag_id)
tagged_items = TaggedItem.objects.filter(tag=tag)
for tagged_item in tagged_items:
tagged_item.tag = new_tag
TaggedItem.objects.filter(tag=tag).update(tag=new_tag)
# tag.delete() #this will delete the selected tags after merge...leaving out for now
if TaggedItem.objects.filter(
tag=new_tag,
content_type=tagged_item.content_type,
object_id=tagged_item.object_id,
).exists():
# we have the new tag as well, so we can just
# remove the tag association
tagged_item.delete()
else:
# point this taggedItem to the new one
tagged_item.tag = new_tag
tagged_item.save()

self.message_user(request, "Tags have been merged", level="success")
# clear the selected_tag_ids from session after merge is complete
Expand Down
2 changes: 1 addition & 1 deletion taggit/templates/admin/taggit/merge_tags_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<form
id="merge-tags-form"
method="post"
action="{% url 'admin:merge_tags' %}"
action="{% url 'admin:taggit_tag_merge_tags' %}"
>
{% csrf_token %} {% for field in form %}
<div>
Expand Down
36 changes: 36 additions & 0 deletions tests/test_admin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.contrib.auth.models import User
from django.test import TestCase
from django.urls import reverse
from taggit.models import Tag

from .models import Food

Expand All @@ -10,6 +11,11 @@ def setUp(self):
super().setUp()
self.apple = Food.objects.create(name="apple")
self.apple.tags.add("Red", "red")
self.pear = Food.objects.create(name="pear")
self.pear.tags.add("red", "RED")
self.peach = Food.objects.create(name="peach")
self.peach.tags.add("red", "Yellow")

user = User.objects.create_superuser(
username="admin", email="[email protected]", password="password"
)
Expand Down Expand Up @@ -40,3 +46,33 @@ def test_get_change(self):
reverse("admin:tests_food_change", args=(self.apple.pk,))
)
self.assertEqual(response.status_code, 200)

def test_tag_merging(self):
response = self.client.get(reverse("admin:taggit_tag_changelist"))

# merging red and RED into Red
pks_to_select = [Tag.objects.get(name="red").pk, Tag.objects.get(name="RED").pk]
response = self.client.post(
reverse("admin:taggit_tag_changelist"),
data={"action": "render_tag_form", "_selected_action": pks_to_select},
)
# we're redirecting
self.assertEqual(response.status_code, 302)
# make sure what we expected got into the session keys
assert "selected_tag_ids" in self.client.session.keys()
self.assertEqual(
self.client.session["selected_tag_ids"], ",".join(map(str, pks_to_select))
)

# let's do the actual merge operation
response = self.client.post(
reverse("admin:taggit_tag_merge_tags"), {"new_tag_name": "Red"}
)
self.assertEqual(response.status_code, 302)

# time to check the result of the merges
self.assertSetEqual({tag.name for tag in self.apple.tags.all()}, {"Red"})
self.assertSetEqual({tag.name for tag in self.pear.tags.all()}, {"Red"})
self.assertSetEqual(
{tag.name for tag in self.peach.tags.all()}, {"Yellow", "Red"}
)

0 comments on commit c6c7bb2

Please sign in to comment.