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

Check for case-insensitive duplicates when creating new tags #461

Merged
merged 3 commits into from Jan 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Expand Up @@ -14,3 +14,4 @@ idle sign <idlesign@yandex.ru>
Charles Leifer
Florian Apolloner <apollo13@apolloner.eu>
Andrew Pryde <andrew@rocketpod.co.uk>
John Whitlock <jwhitlock@mozilla.com>
27 changes: 15 additions & 12 deletions taggit/managers.py
Expand Up @@ -197,36 +197,39 @@ def _to_tag_model_instances(self, tags):
"Cannot add {0} ({1}). Expected {2} or str.".format(
t, type(t), type(self.through.tag_model())))

if getattr(settings, 'TAGGIT_CASE_INSENSITIVE', False):
case_insensitive = getattr(settings, 'TAGGIT_CASE_INSENSITIVE', False)
manager = self.through.tag_model()._default_manager.using(db)

if case_insensitive:
# Some databases can do case-insensitive comparison with IN, which
# would be faster, but we can't rely on it or easily detect it.
existing = []
tags_to_create = []

for name in str_tags:
try:
tag = (self.through.tag_model()._default_manager
.using(db)
.get(name__iexact=name))
tag = manager.get(name__iexact=name)
existing.append(tag)
except self.through.tag_model().DoesNotExist:
tags_to_create.append(name)
else:
# If str_tags has 0 elements Django actually optimizes that to not
# do a query. Malcolm is very smart.
existing = (self.through.tag_model()._default_manager
.using(db)
.filter(name__in=str_tags))

existing = manager.filter(name__in=str_tags)
tags_to_create = str_tags - set(t.name for t in existing)

tag_objs.update(existing)

for new_tag in tags_to_create:
tag_objs.add(
self.through.tag_model()._default_manager
.using(db)
.create(name=new_tag))
if case_insensitive:
try:
tag = manager.get(name__iexact=name)
except self.through.tag_model().DoesNotExist:
tag = manager.create(name=new_tag)
else:
tag = manager.create(name=new_tag)

tag_objs.add(tag)

return tag_objs

Expand Down
7 changes: 7 additions & 0 deletions tests/tests.py
Expand Up @@ -668,6 +668,13 @@ def test_with_case_insensitive_option(self):
orange.tags.add('spain')
self.assertEqual(list(orange.tags.all()), [spain])

@override_settings(TAGGIT_CASE_INSENSITIVE=True)
def test_with_case_insensitive_option_and_creation(self):
orange = self.food_model.objects.create(name="orange")
orange.tags.add('spain', 'Spain')
tag_names = list(orange.tags.names())
self.assertEqual(len(tag_names), 1, tag_names)


class TaggableManagerDirectTestCase(TaggableManagerTestCase):
food_model = DirectFood
Expand Down