1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
import math
import re
import types
from django.db.models.query import QuerySet
from django.utils.encoding import force_unicode, smart_unicode
# Python 2.3 compatibility
if not hasattr(__builtins__, 'set'):
from sets import Set as set
find_tag_re = re.compile(r'[-\w]+', re.U)
def get_tag_name_list(tag_names):
"""
Finds tag names in the given string and return them as a list.
"""
if tag_names is not None:
tag_names = force_unicode(tag_names)
results = find_tag_re.findall(tag_names or '')
return results
def get_tag_list(tags):
"""
Utility function for accepting tag input in a flexible manner.
If a ``Tag`` object is given, it will be returned in a list as
its single occupant.
If given, the tag names in the following will be used to create a
``Tag`` ``QuerySet``:
* A string, which may contain multiple tag names.
* A list or tuple of strings corresponding to tag names.
* A list or tuple of integers corresponding to tag ids.
If given, the following will be returned as-is:
* A list or tuple of ``Tag`` objects.
* A ``Tag`` ``QuerySet``.
"""
from tagging.models import Tag
if isinstance(tags, Tag):
return [tags]
elif isinstance(tags, QuerySet) and tags.model is Tag:
return tags
elif isinstance(tags, types.StringTypes):
return Tag.objects.filter(name__in=get_tag_name_list(tags))
elif isinstance(tags, (types.ListType, types.TupleType)):
if len(tags) == 0:
return tags
contents = set()
for item in tags:
if isinstance(item, types.StringTypes):
contents.add('string')
elif isinstance(item, Tag):
contents.add('tag')
elif isinstance(item, (types.IntType, types.LongType)):
contents.add('int')
if len(contents) == 1:
if 'string' in contents:
return Tag.objects.filter(name__in=[smart_unicode(tag) \
for tag in tags])
elif 'tag' in contents:
return tags
elif 'int' in contents:
return Tag.objects.filter(id__in=tags)
else:
raise ValueError(u'If a list or tuple of tags is provided, they must all be tag names, Tag objects or Tag ids.')
else:
raise ValueError(u'The tag input given was invalid.')
def get_tag(tag):
"""
Utility function for accepting single tag input in a flexible
manner.
If a ``Tag`` object is given it will be returned as-is; if a
string or integer are given, they will be used to lookup the
appropriate ``Tag``.
If no matching tag can be found, ``None`` will be returned.
"""
from tagging.models import Tag
if isinstance(tag, Tag):
return tag
try:
if isinstance(tag, types.StringTypes):
return Tag.objects.get(name=tag)
elif isinstance(tag, (types.IntType, types.LongType)):
return Tag.objects.get(id=tag)
except Tag.DoesNotExist:
pass
return None
# Font size distribution algorithms
LOGARITHMIC, LINEAR = 1, 2
def calculate_cloud(tags, steps=4, distribution=LOGARITHMIC):
"""
Add a ``font_size`` attribute to each tag according to the
frequency of its use, as indicated by its ``count``
attribute.
``steps`` defines the range of font sizes - ``font_size`` will
be an integer between 1 and ``steps`` (inclusive).
``distribution`` defines the type of font size distribution
algorithm which will be used - logarithmic or linear. It must be
either ``tagging.utils.LOGARITHMIC`` or ``tagging.utils.LINEAR``.
The algorithm to scale the tags logarithmically is from a
blog post by Anders Pearson, 'Scaling tag clouds':
http://thraxil.com/users/anders/posts/2005/12/13/scaling-tag-clouds/
"""
if len(tags) > 0:
thresholds = []
counts = [tag.count for tag in tags]
max_weight = float(max(counts))
min_weight = float(min(counts))
# Set up the appropriate thresholds
if distribution == LOGARITHMIC:
thresholds = [math.pow(max_weight - min_weight + 1, float(i) / float(steps)) \
for i in range(1, steps + 1)]
elif distribution == LINEAR:
delta = (max_weight - min_weight) / float(steps)
thresholds = [min_weight + i * delta for i in range(1, steps + 1)]
else:
raise ValueError(u'Invalid font size distribution algorithm specified: %s.' % distribution)
for tag in tags:
font_set = False
for i in range(steps):
if not font_set and tag.count <= thresholds[i]:
tag.font_size = i + 1
font_set = True
return tags
|