app/taggable-mixin/taggable.py
author Lennard de Rijk <ljvderijk@gmail.com>
Sun, 12 Jul 2009 00:45:01 +0200
changeset 2606 03aa33e8600b
parent 2376 feec28b50f1b
permissions -rw-r--r--
Set new Melange version number to 0-5-20090711p1 in app.yaml.template.
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