tag.py
145 lines
| 4.2 KiB
| text/x-python
|
PythonLexer
neko259
|
r1338 | import hashlib | ||
neko259
|
r1590 | from boards.models.attachment import FILE_TYPES_IMAGE | ||
neko259
|
r692 | from django.template.loader import render_to_string | ||
neko259
|
r386 | from django.db import models | ||
neko259
|
r928 | from django.db.models import Count | ||
neko259
|
r692 | from django.core.urlresolvers import reverse | ||
neko259
|
r732 | |||
neko259
|
r1590 | from boards.models import Attachment | ||
neko259
|
r692 | from boards.models.base import Viewable | ||
neko259
|
r1414 | from boards.models.thread import STATUS_ACTIVE, STATUS_BUMPLIMIT, STATUS_ARCHIVE | ||
neko259
|
r973 | from boards.utils import cached_result | ||
neko259
|
r1264 | import boards | ||
neko259
|
r732 | |||
neko259
|
r385 | __author__ = 'neko259' | ||
neko259
|
r1270 | RELATED_TAGS_COUNT = 5 | ||
neko259
|
r385 | class TagManager(models.Manager): | ||
def get_not_empty_tags(self): | ||||
neko259
|
r623 | """ | ||
Gets tags that have non-archived threads. | ||||
""" | ||||
neko259
|
r1269 | return self.annotate(num_threads=Count('thread_tags')).filter(num_threads__gt=0)\ | ||
neko259
|
r1741 | .order_by('name') | ||
neko259
|
r385 | |||
neko259
|
r1027 | def get_tag_url_list(self, tags: list) -> str: | ||
""" | ||||
Gets a comma-separated list of tag links. | ||||
""" | ||||
return ', '.join([tag.get_view() for tag in tags]) | ||||
neko259
|
r385 | |||
neko259
|
r692 | class Tag(models.Model, Viewable): | ||
neko259
|
r385 | """ | ||
neko259
|
r398 | A tag is a text node assigned to the thread. The tag serves as a board | ||
section. There can be multiple tags for each thread | ||||
neko259
|
r385 | """ | ||
objects = TagManager() | ||||
class Meta: | ||||
app_label = 'boards' | ||||
neko259
|
r649 | ordering = ('name',) | ||
neko259
|
r385 | |||
neko259
|
r983 | name = models.CharField(max_length=100, db_index=True, unique=True) | ||
required = models.BooleanField(default=False, db_index=True) | ||||
neko259
|
r1258 | description = models.TextField(blank=True) | ||
neko259
|
r385 | |||
neko259
|
r1367 | parent = models.ForeignKey('Tag', null=True, blank=True, | ||
related_name='children') | ||||
neko259
|
r1348 | |||
neko259
|
r875 | def __str__(self): | ||
neko259
|
r385 | return self.name | ||
neko259
|
r908 | def is_empty(self) -> bool: | ||
neko259
|
r623 | """ | ||
Checks if the tag has some threads. | ||||
""" | ||||
neko259
|
r606 | return self.get_thread_count() == 0 | ||
neko259
|
r385 | |||
neko259
|
r1414 | def get_thread_count(self, status=None) -> int: | ||
neko259
|
r1260 | threads = self.get_threads() | ||
neko259
|
r1414 | if status is not None: | ||
threads = threads.filter(status=status) | ||||
neko259
|
r1260 | return threads.count() | ||
def get_active_thread_count(self) -> int: | ||||
neko259
|
r1414 | return self.get_thread_count(status=STATUS_ACTIVE) | ||
neko259
|
r1383 | |||
def get_bumplimit_thread_count(self) -> int: | ||||
neko259
|
r1414 | return self.get_thread_count(status=STATUS_BUMPLIMIT) | ||
neko259
|
r385 | |||
neko259
|
r1364 | def get_archived_thread_count(self) -> int: | ||
neko259
|
r1414 | return self.get_thread_count(status=STATUS_ARCHIVE) | ||
neko259
|
r1364 | |||
neko259
|
r1160 | def get_absolute_url(self): | ||
neko259
|
r692 | return reverse('tag', kwargs={'tag_name': self.name}) | ||
neko259
|
r908 | def get_threads(self): | ||
neko259
|
r1269 | return self.thread_tags.order_by('-bump_time') | ||
neko259
|
r922 | |||
def is_required(self): | ||||
return self.required | ||||
def get_view(self): | ||||
link = '<a class="tag" href="{}">{}</a>'.format( | ||||
neko259
|
r1150 | self.get_absolute_url(), self.name) | ||
neko259
|
r922 | if self.is_required(): | ||
link = '<b>{}</b>'.format(link) | ||||
return link | ||||
neko259
|
r1107 | @cached_result() | ||
neko259
|
r960 | def get_post_count(self): | ||
neko259
|
r1704 | return self.get_threads().aggregate(num_posts=Count('replies'))['num_posts'] | ||
neko259
|
r1258 | |||
def get_description(self): | ||||
return self.description | ||||
neko259
|
r1264 | |||
neko259
|
r1417 | def get_random_image_post(self, status=[STATUS_ACTIVE, STATUS_BUMPLIMIT]): | ||
neko259
|
r1590 | posts = boards.models.Post.objects.filter(attachments__mimetype__in=FILE_TYPES_IMAGE)\ | ||
.annotate(images_count=Count( | ||||
neko259
|
r1704 | 'attachments')).filter(images_count__gt=0, thread__tags__in=[self]) | ||
neko259
|
r1414 | if status is not None: | ||
neko259
|
r1417 | posts = posts.filter(thread__status__in=status) | ||
neko259
|
r1265 | return posts.order_by('?').first() | ||
neko259
|
r1264 | |||
neko259
|
r1267 | def get_first_letter(self): | ||
return self.name and self.name[0] or '' | ||||
neko259
|
r1269 | |||
def get_related_tags(self): | ||||
neko259
|
r1270 | return set(Tag.objects.filter(thread_tags__in=self.get_threads()).exclude( | ||
neko259
|
r1338 | id=self.id).order_by('?')[:RELATED_TAGS_COUNT]) | ||
@cached_result() | ||||
def get_color(self): | ||||
""" | ||||
Gets color hashed from the tag name. | ||||
""" | ||||
return hashlib.md5(self.name.encode()).hexdigest()[:6] | ||||
neko259
|
r1348 | |||
def get_parent(self): | ||||
return self.parent | ||||
def get_all_parents(self): | ||||
neko259
|
r1361 | parents = list() | ||
neko259
|
r1348 | parent = self.get_parent() | ||
if parent and parent not in parents: | ||||
neko259
|
r1361 | parents.insert(0, parent) | ||
parents = parent.get_all_parents() + parents | ||||
neko259
|
r1348 | |||
return parents | ||||
def get_children(self): | ||||
return self.children | ||||
neko259
|
r1419 | |||
def get_images(self): | ||||
neko259
|
r1590 | return Attachment.objects.filter( | ||
neko259
|
r1591 | attachment_posts__thread__tags__in=[self]).filter( | ||
neko259
|
r1729 | mimetype__in=FILE_TYPES_IMAGE).order_by('-attachment_posts__pub_time') | ||