Skip to content

Commit 1e829d4

Browse files
committed
Fixed issue #28 — properly update TagField tag instance cache when loading the object to keep everything in sync. Thanks ebartels and carljm for the legwork.
git-svn-id: https://django-tagging.googlecode.com/svn/trunk@170 83e7428b-ec2a-0410-86f2-bf466d0e5e72
1 parent 9b760f8 commit 1e829d4

File tree

3 files changed

+45
-10
lines changed

3 files changed

+45
-10
lines changed

tagging/fields.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class TagField(CharField):
1818
def __init__(self, *args, **kwargs):
1919
kwargs['max_length'] = kwargs.get('max_length', 255)
2020
kwargs['blank'] = kwargs.get('blank', True)
21+
kwargs['default'] = kwargs.get('default', '')
2122
super(TagField, self).__init__(*args, **kwargs)
2223

2324
def contribute_to_class(self, cls, name):
@@ -29,6 +30,9 @@ def contribute_to_class(self, cls, name):
2930
# Save tags back to the database post-save
3031
signals.post_save.connect(self._save, cls, True)
3132

33+
# Update tags from Tag objects post-init
34+
signals.post_init.connect(self._update, cls, True)
35+
3236
def __get__(self, instance, owner=None):
3337
"""
3438
Tag getter. Returns an instance's tags if accessed on an instance, and
@@ -52,13 +56,6 @@ class Link(models.Model):
5256
if instance is None:
5357
return edit_string_for_tags(Tag.objects.usage_for_model(owner))
5458

55-
tags = self._get_instance_tag_cache(instance)
56-
if tags is None:
57-
if instance.pk is None:
58-
self._set_instance_tag_cache(instance, '')
59-
else:
60-
self._set_instance_tag_cache(
61-
instance, edit_string_for_tags(Tag.objects.get_for_object(instance)))
6259
return self._get_instance_tag_cache(instance)
6360

6461
def __set__(self, instance, value):
@@ -76,8 +73,14 @@ def _save(self, **kwargs): #signal, sender, instance):
7673
Save tags back to the database
7774
"""
7875
tags = self._get_instance_tag_cache(kwargs['instance'])
79-
if tags is not None:
80-
Tag.objects.update_tags(kwargs['instance'], tags)
76+
Tag.objects.update_tags(kwargs['instance'], tags)
77+
78+
def _update(self, **kwargs): #signal, sender, instance):
79+
"""
80+
Update tag cache from TaggedItem objects.
81+
"""
82+
instance = kwargs['instance']
83+
self._update_instance_tag_cache(instance)
8184

8285
def __delete__(self, instance):
8386
"""
@@ -97,6 +100,15 @@ def _set_instance_tag_cache(self, instance, tags):
97100
"""
98101
setattr(instance, '_%s_cache' % self.attname, tags)
99102

103+
def _update_instance_tag_cache(self, instance):
104+
"""
105+
Helper: update an instance's tag cache from actual Tags.
106+
"""
107+
# for an unsaved object, leave the default value alone
108+
if instance.pk is not None:
109+
tags = edit_string_for_tags(Tag.objects.get_for_object(instance))
110+
self._set_instance_tag_cache(instance, tags)
111+
100112
def get_internal_type(self):
101113
return 'CharField'
102114

tagging/tests/models.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,7 @@ class Meta:
3636

3737
class FormTest(models.Model):
3838
tags = TagField('Test', help_text='Test')
39+
40+
class FormTestNull(models.Model):
41+
tags = TagField(null=True)
42+

tagging/tests/tests.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from tagging.forms import TagField
88
from tagging import settings
99
from tagging.models import Tag, TaggedItem
10-
from tagging.tests.models import Article, Link, Perch, Parrot, FormTest
10+
from tagging.tests.models import Article, Link, Perch, Parrot, FormTest, FormTestNull
1111
from tagging.utils import calculate_cloud, edit_string_for_tags, get_tag_list, get_tag, parse_tag_input
1212
from tagging.utils import LINEAR
1313

@@ -369,6 +369,25 @@ def test_update_via_tags_field(self):
369369
f1.save()
370370
tags = Tag.objects.get_for_object(f1)
371371
self.assertEquals(len(tags), 0)
372+
373+
def test_update_via_tags(self):
374+
f1 = FormTest.objects.create(tags=u'one two three')
375+
Tag.objects.get(name='three').delete()
376+
t2 = Tag.objects.get(name='two')
377+
t2.name = 'new'
378+
t2.save()
379+
f1again = FormTest.objects.get(pk=f1.pk)
380+
self.failIf('three' in f1again.tags)
381+
self.failIf('two' in f1again.tags)
382+
self.failUnless('new' in f1again.tags)
383+
384+
def test_creation_without_specifying_tags(self):
385+
f1 = FormTest()
386+
self.assertEquals(f1.tags, '')
387+
388+
def test_creation_with_nullable_tags_field(self):
389+
f1 = FormTestNull()
390+
self.assertEquals(f1.tags, '')
372391

373392
class TestSettings(TestCase):
374393
def setUp(self):

0 commit comments

Comments
 (0)