bgneal@75: """ bgneal@75: Models for the forums application. bgneal@75: """ bgneal@75: from django.db import models bgneal@75: from django.contrib.auth.models import User, Group bgneal@75: from django.template.loader import render_to_string bgneal@75: bgneal@75: bgneal@75: class Category(models.Model): bgneal@75: name = models.CharField(max_length=80) bgneal@75: slug = models.SlugField(max_length=80) bgneal@75: position = models.IntegerField(blank=True, default=0) bgneal@75: groups = models.ManyToManyField(Group, blank=True, null=True, bgneal@75: help_text="If groups are assigned to this category, only members" \ bgneal@75: " of those groups can view this category.") bgneal@75: bgneal@75: class Meta: bgneal@75: ordering = ('position', ) bgneal@75: verbose_name_plural = 'Categories' bgneal@75: bgneal@75: def __unicode__(self): bgneal@75: return self.name bgneal@75: bgneal@75: bgneal@75: class Forum(models.Model): bgneal@75: category = models.ForeignKey(Category, related_name='forums') bgneal@75: name = models.CharField(max_length=80) bgneal@75: slug = models.SlugField(max_length=80) bgneal@75: description = models.TextField(blank=True, default='') bgneal@75: position = models.IntegerField(blank=True, default=0) bgneal@75: moderators = models.ManyToManyField(Group, blank=True, null=True) bgneal@75: bgneal@75: # denormalized fields to reduce database hits bgneal@75: topic_count = models.IntegerField(blank=True, default=0) bgneal@75: post_count = models.IntegerField(blank=True, default=0) bgneal@75: last_post = models.OneToOneField('Post', blank=True, null=True, bgneal@75: related_name='parent_forum') bgneal@75: bgneal@75: class Meta: bgneal@75: ordering = ('position', ) bgneal@75: bgneal@75: def __unicode__(self): bgneal@75: return self.name bgneal@75: bgneal@81: @models.permalink bgneal@81: def get_absolute_url(self): bgneal@81: return ('forums-forum_index', [self.slug]) bgneal@81: bgneal@75: def topic_count_update(self): bgneal@75: """Call to notify the forum that its topic count has been updated.""" bgneal@75: self.topic_count = Topic.objects.filter(forum=self).count() bgneal@75: bgneal@75: def post_count_update(self): bgneal@75: """Call to notify the forum that its post count has been updated.""" bgneal@75: my_posts = Post.objects.filter(topic__forum=self) bgneal@75: self.post_count = my_posts.count() bgneal@75: if self.post_count > 0: bgneal@75: self.last_post = my_posts[self.post_count - 1] bgneal@75: else: bgneal@75: self.last_post = None bgneal@75: bgneal@75: bgneal@75: class Topic(models.Model): bgneal@75: forum = models.ForeignKey(Forum, related_name='topics') bgneal@75: name = models.CharField(max_length=255) bgneal@75: creation_date = models.DateTimeField(auto_now_add=True) bgneal@75: user = models.ForeignKey(User) bgneal@75: view_count = models.IntegerField(blank=True, default=0) bgneal@75: sticky = models.BooleanField(blank=True, default=False) bgneal@75: locked = models.BooleanField(blank=True, default=False) bgneal@75: bgneal@75: # denormalized fields to reduce database hits bgneal@75: post_count = models.IntegerField(blank=True, default=0) bgneal@75: update_date = models.DateTimeField(auto_now=True) bgneal@75: last_post = models.OneToOneField('Post', blank=True, null=True, bgneal@75: related_name='parent_topic') bgneal@75: bgneal@75: class Meta: bgneal@75: ordering = ('-sticky', '-update_date', ) bgneal@75: bgneal@75: def __unicode__(self): bgneal@75: return self.name bgneal@75: bgneal@82: @models.permalink bgneal@82: def get_absolute_url(self): bgneal@82: return ('forums-topic_index', [self.pk]) bgneal@82: bgneal@75: def post_count_update(self): bgneal@75: """ bgneal@75: Call this function to notify the topic instance that its post count bgneal@75: has changed. bgneal@75: """ bgneal@75: my_posts = Post.objects.filter(topic=self) bgneal@75: self.post_count = my_posts.count() bgneal@75: if self.post_count > 0: bgneal@75: self.last_post = my_posts[self.post_count - 1] bgneal@75: self.update_date = self.last_post.creation_date bgneal@75: else: bgneal@75: self.last_post = None bgneal@75: self.update_date = self.creation_date bgneal@75: bgneal@83: def reply_count(self): bgneal@83: """ bgneal@83: Returns the number of replies to a topic. The first post bgneal@83: doesn't count as a reply. bgneal@83: """ bgneal@83: if self.post_count > 1: bgneal@83: return self.post_count - 1 bgneal@83: return 0 bgneal@83: bgneal@75: bgneal@75: class Post(models.Model): bgneal@75: topic = models.ForeignKey(Topic, related_name='posts') bgneal@75: user = models.ForeignKey(User, related_name='posts') bgneal@75: creation_date = models.DateTimeField(auto_now_add=True) bgneal@75: update_date = models.DateTimeField(auto_now=True) bgneal@75: body = models.TextField() bgneal@75: html = models.TextField() bgneal@83: user_ip = models.IPAddressField(blank=True, default='', null=True) bgneal@75: bgneal@75: class Meta: bgneal@75: ordering = ('creation_date', ) bgneal@75: bgneal@75: def summary(self): bgneal@75: LIMIT = 50 bgneal@75: if len(self.body) < LIMIT: bgneal@75: return self.body bgneal@75: return self.body[:LIMIT] + '...' bgneal@75: bgneal@75: def __unicode__(self): bgneal@75: return self.summary() bgneal@75: bgneal@75: def save(self, *args, **kwargs): bgneal@75: html = render_to_string('forums/post.html', {'data': self.body}) bgneal@75: self.html = html.strip() bgneal@75: super(Post, self).save(*args, **kwargs) bgneal@75: bgneal@75: def delete(self, *args, **kwargs): bgneal@75: first_post_id = self.topic.posts.all()[0].id bgneal@75: super(Post, self).delete(*args, **kwargs) bgneal@75: if self.id == first_post_id: bgneal@75: self.topic.delete() bgneal@75: bgneal@75: # TODO: A "read" table bgneal@75: # TODO: A flagged post table