Commits

Anonymous committed 6f75398

[0.3.X] 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.

Backport of r170 from trunk

  • Participants
  • Parent commits 664b709
  • Branches 0.3.X

Comments (0)

Files changed (3)

File tagging/fields.py

     def __init__(self, *args, **kwargs):
         kwargs['max_length'] = kwargs.get('max_length', 255)
         kwargs['blank'] = kwargs.get('blank', True)
+        kwargs['default'] = kwargs.get('default', '')
         super(TagField, self).__init__(*args, **kwargs)
 
     def contribute_to_class(self, cls, name):
         # Save tags back to the database post-save
         signals.post_save.connect(self._save, cls, True)
 
+        # Update tags from Tag objects post-init
+        signals.post_init.connect(self._update, cls, True)
+
     def __get__(self, instance, owner=None):
         """
         Tag getter. Returns an instance's tags if accessed on an instance, and
         if instance is None:
             return edit_string_for_tags(Tag.objects.usage_for_model(owner))
 
-        tags = self._get_instance_tag_cache(instance)
-        if tags is None:
-            if instance.pk is None:
-                self._set_instance_tag_cache(instance, '')
-            else:
-                self._set_instance_tag_cache(
-                    instance, edit_string_for_tags(Tag.objects.get_for_object(instance)))
         return self._get_instance_tag_cache(instance)
 
     def __set__(self, instance, value):
         Save tags back to the database
         """
         tags = self._get_instance_tag_cache(kwargs['instance'])
-        if tags is not None:
-            Tag.objects.update_tags(kwargs['instance'], tags)
+        Tag.objects.update_tags(kwargs['instance'], tags)
+
+    def _update(self, **kwargs): #signal, sender, instance):
+        """
+        Update tag cache from TaggedItem objects.
+        """
+        instance = kwargs['instance']
+        self._update_instance_tag_cache(instance)
 
     def __delete__(self, instance):
         """
         """
         setattr(instance, '_%s_cache' % self.attname, tags)
 
+    def _update_instance_tag_cache(self, instance):
+        """
+        Helper: update an instance's tag cache from actual Tags.
+        """
+        # for an unsaved object, leave the default value alone
+        if instance.pk is not None:
+            tags = edit_string_for_tags(Tag.objects.get_for_object(instance))
+            self._set_instance_tag_cache(instance, tags)
+
     def get_internal_type(self):
         return 'CharField'
 

File tagging/tests/models.py

 
 class FormTest(models.Model):
     tags = TagField('Test', help_text='Test')
+
+class FormTestNull(models.Model):
+    tags = TagField(null=True)
+

File tagging/tests/tests.py

 from tagging.forms import TagField
 from tagging import settings
 from tagging.models import Tag, TaggedItem
-from tagging.tests.models import Article, Link, Perch, Parrot, FormTest
+from tagging.tests.models import Article, Link, Perch, Parrot, FormTest, FormTestNull
 from tagging.utils import calculate_cloud, edit_string_for_tags, get_tag_list, get_tag, parse_tag_input
 from tagging.utils import LINEAR
 
         f1.save()
         tags = Tag.objects.get_for_object(f1)
         self.assertEquals(len(tags), 0)
+
+    def test_update_via_tags(self):
+        f1 = FormTest.objects.create(tags=u'one two three')
+        Tag.objects.get(name='three').delete()
+        t2 = Tag.objects.get(name='two')
+        t2.name = 'new'
+        t2.save()
+        f1again = FormTest.objects.get(pk=f1.pk)
+        self.failIf('three' in f1again.tags)
+        self.failIf('two' in f1again.tags)
+        self.failUnless('new' in f1again.tags)
+
+    def test_creation_without_specifying_tags(self):
+        f1 = FormTest()
+        self.assertEquals(f1.tags, '')
+
+    def test_creation_with_nullable_tags_field(self):
+        f1 = FormTestNull()
+        self.assertEquals(f1.tags, '')
         
 class TestSettings(TestCase):
     def setUp(self):