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
|
import re
from django.db import models
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _
from askbot.models.base import BaseQuerySetManager
from askbot import const
def tags_match_some_wildcard(tag_names, wildcard_tags):
"""Same as
:meth:`~askbot.models.tag.TagQuerySet.tags_match_some_wildcard`
except it works on tag name strings
"""
for tag_name in tag_names:
for wildcard_tag in sorted(wildcard_tags):
if tag_name.startswith(wildcard_tag[:-1]):
return True
return False
def get_mandatory_tags():
"""returns list of mandatory tags,
or an empty list, if there aren't any"""
from askbot.conf import settings as askbot_settings
raw_mandatory_tags = askbot_settings.MANDATORY_TAGS.strip()
if len(raw_mandatory_tags) == 0:
return []
else:
split_re = re.compile(const.TAG_SPLIT_REGEX)
return split_re.split(raw_mandatory_tags)
class TagQuerySet(models.query.QuerySet):
def get_valid_tags(self, page_size):
tags = self.all().filter(deleted=False).exclude(used_count=0).order_by("-id")[:page_size]
return tags
def update_use_counts(self, tags):
"""Updates the given Tags with their current use counts."""
for tag in tags:
tag.used_count = tag.threads.count()
tag.save()
def tags_match_some_wildcard(self, wildcard_tags = None):
"""True if any one of the tags in the query set
matches a wildcard
:arg:`wildcard_tags` is an iterable of wildcard tag strings
todo: refactor to use :func:`tags_match_some_wildcard`
"""
for tag in self.all():
for wildcard_tag in sorted(wildcard_tags):
if tag.name.startswith(wildcard_tag[:-1]):
return True
return False
def get_by_wildcards(self, wildcards = None):
"""returns query set of tags that match the wildcard tags
wildcard tag is guaranteed to end with an asterisk and has
at least one character preceding the the asterisk. and there
is only one asterisk in the entire name
"""
if wildcards is None or len(wildcards) == 0:
return self.none()
first_tag = wildcards.pop()
tag_filter = models.Q(name__startswith = first_tag[:-1])
for next_tag in wildcards:
tag_filter |= models.Q(name__startswith = next_tag[:-1])
return self.filter(tag_filter)
def get_related_to_search(self, threads, ignored_tag_names):
"""Returns at least tag names, along with use counts"""
tags = self.filter(threads__in=threads).annotate(local_used_count=models.Count('id')).order_by('-local_used_count', 'name')
if ignored_tag_names:
tags = tags.exclude(name__in=ignored_tag_names)
tags = tags.exclude(deleted = True)
return list(tags[:50])
class TagManager(BaseQuerySetManager):
"""chainable custom filter query set manager
for :class:``~askbot.models.Tag`` objects
"""
def get_query_set(self):
return TagQuerySet(self.model)
class Tag(models.Model):
name = models.CharField(max_length=255, unique=True)
created_by = models.ForeignKey(User, related_name='created_tags')
# Denormalised data
used_count = models.PositiveIntegerField(default=0)
deleted = models.BooleanField(default=False)
deleted_at = models.DateTimeField(null=True, blank=True)
deleted_by = models.ForeignKey(User, null=True, blank=True, related_name='deleted_tags')
objects = TagManager()
class Meta:
app_label = 'askbot'
db_table = u'tag'
ordering = ('-used_count', 'name')
def __unicode__(self):
return self.name
class MarkedTag(models.Model):
TAG_MARK_REASONS = (('good', _('interesting')), ('bad', _('ignored')))
tag = models.ForeignKey('Tag', related_name='user_selections')
user = models.ForeignKey(User, related_name='tag_selections')
reason = models.CharField(max_length=16, choices=TAG_MARK_REASONS)
class Meta:
app_label = 'askbot'
|