Skip to content

Commit d8889a6

Browse files
authored
Merge pull request #908 from guel-codes/682-orphaned-tags
[#682] - Remove Orphaned Tags
2 parents ffa9d60 + 3b15951 commit d8889a6

File tree

3 files changed

+71
-0
lines changed

3 files changed

+71
-0
lines changed

CHANGELOG.rst

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Changelog
33

44
(Unreleased)
55
~~~~~~~~~~~~
6+
* Added a management command (``remove_orphaned_tags``) to remove orphaned tags
67

78
6.0.0 (2024-07-27)
89
~~~~~~~~~~~~~~~~~~
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from django.core.management.base import BaseCommand
2+
3+
from taggit.models import Tag
4+
5+
6+
class Command(BaseCommand):
7+
help = "Remove orphaned tags"
8+
9+
def handle(self, *args, **options):
10+
orphaned_tags = Tag.objects.filter(taggit_taggeditem_items=None)
11+
count = orphaned_tags.delete()
12+
self.stdout.write(f"Successfully removed {count} orphaned tags")

tests/test_remove_orphaned_tags.py

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from django.core.management import call_command
2+
from django.test import TestCase
3+
4+
from taggit.models import Tag
5+
from tests.models import Food, HousePet
6+
7+
8+
class RemoveOrphanedTagsTests(TestCase):
9+
def setUp(self):
10+
# Create some tags, some orphaned and some not
11+
self.orphan_tag1 = Tag.objects.create(name="Orphan1")
12+
self.orphan_tag2 = Tag.objects.create(name="Orphan2")
13+
self.used_tag = Tag.objects.create(name="Used")
14+
15+
# Create instances of Food and HousePet and tag them
16+
self.food_item = Food.objects.create(name="Apple")
17+
self.pet_item = HousePet.objects.create(name="Fido")
18+
19+
self.food_item.tags.add(self.used_tag)
20+
self.pet_item.tags.add(self.used_tag)
21+
22+
def test_remove_orphaned_tags(self):
23+
# Ensure the setup is correct
24+
self.assertEqual(Tag.objects.count(), 3)
25+
self.assertEqual(Tag.objects.filter(taggit_taggeditem_items=None).count(), 2)
26+
27+
# Call the management command to remove orphaned tags
28+
call_command("remove_orphaned_tags")
29+
30+
# Check the count of tags after running the command
31+
self.assertEqual(Tag.objects.count(), 1)
32+
self.assertEqual(Tag.objects.filter(taggit_taggeditem_items=None).count(), 0)
33+
34+
# Ensure that the used tag still exists
35+
self.assertTrue(Tag.objects.filter(name="Used").exists())
36+
self.assertFalse(Tag.objects.filter(name="Orphan1").exists())
37+
self.assertFalse(Tag.objects.filter(name="Orphan2").exists())
38+
39+
def test_no_orphaned_tags(self):
40+
# Ensure the setup is correct
41+
self.assertEqual(Tag.objects.count(), 3)
42+
self.assertEqual(Tag.objects.filter(taggit_taggeditem_items=None).count(), 2)
43+
44+
# Add used_tag to food_item to make no tags orphaned
45+
self.food_item.tags.add(self.orphan_tag1)
46+
self.food_item.tags.add(self.orphan_tag2)
47+
48+
# Call the management command to remove orphaned tags
49+
call_command("remove_orphaned_tags")
50+
51+
# Check the count of tags after running the command
52+
self.assertEqual(Tag.objects.count(), 3)
53+
self.assertEqual(Tag.objects.filter(taggit_taggeditem_items=None).count(), 0)
54+
55+
# Ensure all tags still exist
56+
self.assertTrue(Tag.objects.filter(name="Used").exists())
57+
self.assertTrue(Tag.objects.filter(name="Orphan1").exists())
58+
self.assertTrue(Tag.objects.filter(name="Orphan2").exists())

0 commit comments

Comments
 (0)