web/lib/tagging/fields.py
changeset 11 f236caaceb43
equal deleted inserted replaced
10:7207a5a27b8f 11:f236caaceb43
       
     1 """
       
     2 A custom Model Field for tagging.
       
     3 """
       
     4 from django.db.models import signals
       
     5 from django.db.models.fields import CharField
       
     6 from django.utils.translation import ugettext_lazy as _
       
     7 
       
     8 from tagging import settings
       
     9 from tagging.models import Tag
       
    10 from tagging.utils import edit_string_for_tags
       
    11 
       
    12 class TagField(CharField):
       
    13     """
       
    14     A "special" character field that actually works as a relationship to tags
       
    15     "under the hood". This exposes a space-separated string of tags, but does
       
    16     the splitting/reordering/etc. under the hood.
       
    17     """
       
    18     def __init__(self, *args, **kwargs):
       
    19         kwargs['max_length'] = kwargs.get('max_length', 255)
       
    20         kwargs['blank'] = kwargs.get('blank', True)
       
    21         super(TagField, self).__init__(*args, **kwargs)
       
    22 
       
    23     def contribute_to_class(self, cls, name):
       
    24         super(TagField, self).contribute_to_class(cls, name)
       
    25 
       
    26         # Make this object the descriptor for field access.
       
    27         setattr(cls, self.name, self)
       
    28 
       
    29         # Save tags back to the database post-save
       
    30         signals.post_save.connect(self._save, cls, True)
       
    31 
       
    32     def __get__(self, instance, owner=None):
       
    33         """
       
    34         Tag getter. Returns an instance's tags if accessed on an instance, and
       
    35         all of a model's tags if called on a class. That is, this model::
       
    36 
       
    37            class Link(models.Model):
       
    38                ...
       
    39                tags = TagField()
       
    40 
       
    41         Lets you do both of these::
       
    42 
       
    43            >>> l = Link.objects.get(...)
       
    44            >>> l.tags
       
    45            'tag1 tag2 tag3'
       
    46 
       
    47            >>> Link.tags
       
    48            'tag1 tag2 tag3 tag4'
       
    49 
       
    50         """
       
    51         # Handle access on the model (i.e. Link.tags)
       
    52         if instance is None:
       
    53             return edit_string_for_tags(Tag.objects.usage_for_model(owner))
       
    54 
       
    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)))
       
    62         return self._get_instance_tag_cache(instance)
       
    63 
       
    64     def __set__(self, instance, value):
       
    65         """
       
    66         Set an object's tags.
       
    67         """
       
    68         if instance is None:
       
    69             raise AttributeError(_('%s can only be set on instances.') % self.name)
       
    70         if settings.FORCE_LOWERCASE_TAGS and value is not None:
       
    71             value = value.lower()
       
    72         self._set_instance_tag_cache(instance, value)
       
    73 
       
    74     def _save(self, **kwargs): #signal, sender, instance):
       
    75         """
       
    76         Save tags back to the database
       
    77         """
       
    78         tags = self._get_instance_tag_cache(kwargs['instance'])
       
    79         if tags is not None:
       
    80             Tag.objects.update_tags(kwargs['instance'], tags)
       
    81 
       
    82     def __delete__(self, instance):
       
    83         """
       
    84         Clear all of an object's tags.
       
    85         """
       
    86         self._set_instance_tag_cache(instance, '')
       
    87 
       
    88     def _get_instance_tag_cache(self, instance):
       
    89         """
       
    90         Helper: get an instance's tag cache.
       
    91         """
       
    92         return getattr(instance, '_%s_cache' % self.attname, None)
       
    93 
       
    94     def _set_instance_tag_cache(self, instance, tags):
       
    95         """
       
    96         Helper: set an instance's tag cache.
       
    97         """
       
    98         setattr(instance, '_%s_cache' % self.attname, tags)
       
    99 
       
   100     def get_internal_type(self):
       
   101         return 'CharField'
       
   102 
       
   103     def formfield(self, **kwargs):
       
   104         from tagging import forms
       
   105         defaults = {'form_class': forms.TagField}
       
   106         defaults.update(kwargs)
       
   107         return super(TagField, self).formfield(**defaults)