app/taggable-mixin/taggable.py
author Pawel Solyga <Pawel.Solyga@gmail.com>
Mon, 01 Jun 2009 22:23:46 +0200
changeset 2376 feec28b50f1b
parent 2368 e07c425c7135
permissions -rw-r--r--
Extend taggable-mixin to support different Tag models. Usage is pretty simple. Tag model is default in Taggable constructor but you can call it with different model like GHOPTaskType that inherits from Tag model. Both Taggable and Tag models have been updated and they don't use hardcoded Tag model anymore and instead use cls of class methods or self.__class__. In case of Taggable it's self.__tag_model.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2368
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
     1
from google.appengine.ext import db
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
     2
import string
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
     3
    
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
     4
class Tag(db.Model):
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
     5
    "Google AppEngine model for store of tags."
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
     6
    
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
     7
    tag = db.StringProperty(required=True)
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
     8
    "The actual string value of the tag."
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
     9
    
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    10
    added = db.DateTimeProperty(auto_now_add=True)
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    11
    "The date and time that the tag was first added to the datastore."
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    12
    
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    13
    tagged = db.ListProperty(db.Key)
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    14
    "A List of db.Key values for the datastore objects that have been tagged with this tag value."
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    15
    
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    16
    tagged_count = db.IntegerProperty(default=0)
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    17
    "The number of entities in tagged."
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    18
2376
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
    19
    @classmethod
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
    20
    def __key_name(cls, tag_name):
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
    21
        return cls.__name__ + '_' + tag_name
2368
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    22
    
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    23
    def remove_tagged(self, key):
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    24
        def remove_tagged_txn():
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    25
            if key in self.tagged:
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    26
                self.tagged.remove(key)
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    27
                self.tagged_count -= 1
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    28
                self.put()
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    29
        db.run_in_transaction(remove_tagged_txn)
2376
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
    30
        self.__class__.expire_cached_tags()
2368
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    31
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    32
    def add_tagged(self, key):
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    33
        def add_tagged_txn():
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    34
            if key not in self.tagged:
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    35
                self.tagged.append(key)
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    36
                self.tagged_count += 1
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    37
                self.put()
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    38
        db.run_in_transaction(add_tagged_txn)
2376
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
    39
        self.__class__.expire_cached_tags()
2368
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    40
    
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    41
    def clear_tagged(self):
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    42
        def clear_tagged_txn():
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    43
            self.tagged = []
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    44
            self.tagged_count = 0
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    45
            self.put()
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    46
        db.run_in_transaction(clear_tagged_txn)
2376
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
    47
        self.__class__.expire_cached_tags()
2368
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    48
        
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    49
    @classmethod
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    50
    def get_by_name(cls, tag_name):
2376
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
    51
        return cls.get_by_key_name(cls.__key_name(tag_name))
2368
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    52
    
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    53
    @classmethod
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    54
    def get_tags_for_key(cls, key):
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    55
        "Set the tags for the datastore object represented by key."
2376
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
    56
        tags = db.Query(cls).filter('tagged =', key).fetch(1000)
2368
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    57
        return tags
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    58
    
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    59
    @classmethod
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    60
    def get_or_create(cls, tag_name):
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    61
        "Get the Tag object that has the tag value given by tag_value."
2376
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
    62
        tag_key_name = cls.__key_name(tag_name)
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
    63
        existing_tag = cls.get_by_key_name(tag_key_name)
2368
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    64
        if existing_tag is None:
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    65
            # The tag does not yet exist, so create it.
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    66
            def create_tag_txn():
2376
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
    67
                new_tag = cls(key_name=tag_key_name, tag=tag_name)
2368
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    68
                new_tag.put()
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    69
                return new_tag
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    70
            existing_tag = db.run_in_transaction(create_tag_txn)
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    71
        return existing_tag
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    72
    
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    73
    @classmethod
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    74
    def get_tags_by_frequency(cls, limit=1000):
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    75
        """Return a list of Tags sorted by the number of objects to which they have been applied,
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    76
        most frequently-used first.  If limit is given, return only that many tags; otherwise,
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    77
        return all."""
2376
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
    78
        tag_list = db.Query(cls).filter('tagged_count >', 0).order("-tagged_count").fetch(limit)
2368
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    79
            
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    80
        return tag_list
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    81
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    82
    @classmethod
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    83
    def get_tags_by_name(cls, limit=1000, ascending=True):
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    84
        """Return a list of Tags sorted alphabetically by the name of the tag.
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    85
        If a limit is given, return only that many tags; otherwise, return all.
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    86
        If ascending is True, sort from a-z; otherwise, sort from z-a."""
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    87
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    88
        from google.appengine.api import memcache
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    89
2376
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
    90
        cache_name = cls.__name__ + '_tags_by_name'
2368
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    91
        if ascending:
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    92
            cache_name += '_asc'
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    93
        else:
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    94
            cache_name += '_desc'
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    95
            
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    96
        tags = memcache.get(cache_name)
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    97
        if tags is None or len(tags) < limit:
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    98
            order_by = "tag"
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
    99
            if not ascending:
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   100
                order_by = "-tag"
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   101
            
2376
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
   102
            tags = db.Query(cls).order(order_by).fetch(limit)
2368
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   103
            memcache.add(cache_name, tags, 3600)
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   104
        else:
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   105
            if len(tags) > limit:
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   106
                # Return only as many as requested.
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   107
                tags = tags[:limit]
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   108
                
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   109
        return tags
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   110
        
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   111
    
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   112
    @classmethod
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   113
    def popular_tags(cls, limit=5):
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   114
        from google.appengine.api import memcache
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   115
        
2376
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
   116
        tags = memcache.get(cls.__name__ + '_popular_tags')
2368
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   117
        if tags is None:
2376
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
   118
            tags = cls.get_tags_by_frequency(limit)
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
   119
            memcache.add(cls.__name__ + '_popular_tags', tags, 3600)
2368
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   120
        
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   121
        return tags
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   122
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   123
    @classmethod
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   124
    def expire_cached_tags(cls):
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   125
        from google.appengine.api import memcache
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   126
        
2376
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
   127
        memcache.delete(cls.__name__ + '_popular_tags')
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
   128
        memcache.delete(cls.__name__ + '_tags_by_name_asc')
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
   129
        memcache.delete(cls.__name__ + '_tags_by_name_desc')
2368
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   130
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   131
class Taggable:
2376
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
   132
    """A mixin class that is used for making Google AppEngine Model classes taggable.
2368
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   133
        Usage:
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   134
            class Post(db.Model, taggable.Taggable):
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   135
                body = db.TextProperty(required = True)
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   136
                title = db.StringProperty()
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   137
                added = db.DateTimeProperty(auto_now_add=True)
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   138
                edited = db.DateTimeProperty()
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   139
            
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   140
                def __init__(self, parent=None, key_name=None, app=None, **entity_values):
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   141
                    db.Model.__init__(self, parent, key_name, app, **entity_values)
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   142
                    taggable.Taggable.__init__(self)
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   143
    """
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   144
    
2376
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
   145
    def __init__(self, tag_model = Tag):
2368
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   146
        self.__tags = None
2376
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
   147
        self.__tag_model = tag_model
2368
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   148
        self.tag_separator = ","
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   149
        """The string that is used to separate individual tags in a string
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   150
        representation of a list of tags.  Used by tags_string() to join the tags
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   151
        into a string representation and tags setter to split a string into
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   152
        individual tags."""
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   153
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   154
    def __get_tags(self):
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   155
        "Get a List of Tag objects for all Tags that apply to this object."
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   156
        if self.__tags is None or len(self.__tags) == 0:
2376
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
   157
            self.__tags = self.__tag_model.get_tags_for_key(self.key())
2368
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   158
        return self.__tags
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   159
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   160
    def __set_tags(self, tags):
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   161
        import types
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   162
        if type(tags) is types.UnicodeType:
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   163
            # Convert unicode to a plain string
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   164
            tags = str(tags)
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   165
        if type(tags) is types.StringType:
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   166
            # Tags is a string, split it on tag_seperator into a list
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   167
            tags = string.split(tags, self.tag_separator)
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   168
        if type(tags) is types.ListType:
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   169
            self.__get_tags()
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   170
            # Firstly, we will check to see if any tags have been removed.
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   171
            # Iterate over a copy of __tags, as we may need to modify __tags
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   172
            for each_tag in self.__tags[:]:
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   173
                if each_tag not in tags:
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   174
                    # A tag that was previously assigned to this entity is
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   175
                    # missing in the list that is being assigned, so we
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   176
                    # disassocaite this entity and the tag.
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   177
                    each_tag.remove_tagged(self.key())
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   178
                    self.__tags.remove(each_tag)
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   179
            # Secondly, we will check to see if any tags have been added.
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   180
            for each_tag in tags:
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   181
                each_tag = string.strip(each_tag)
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   182
                if len(each_tag) > 0 and each_tag not in self.__tags:
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   183
                    # A tag that was not previously assigned to this entity
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   184
                    # is present in the list that is being assigned, so we
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   185
                    # associate this entity with the tag.
2376
feec28b50f1b Extend taggable-mixin to support different Tag models.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents: 2368
diff changeset
   186
                    tag = self.__tag_model.get_or_create(each_tag)
2368
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   187
                    tag.add_tagged(self.key())
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   188
                    self.__tags.append(tag)
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   189
        else:
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   190
            raise Exception, "tags must be either a unicode, a string or a list"
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   191
        
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   192
    tags = property(__get_tags, __set_tags, None, None)
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   193
    
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   194
    def tags_string(self):
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   195
        "Create a formatted string version of this entity's tags"
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   196
        to_str = ""
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   197
        for each_tag in self.tags:
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   198
            to_str += each_tag.tag
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   199
            if each_tag != self.tags[-1]:
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   200
                to_str += self.tag_separator
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   201
        return to_str
e07c425c7135 Add taggable-mixin to Melange repository.
Pawel Solyga <Pawel.Solyga@gmail.com>
parents:
diff changeset
   202