bgneal@75
|
1 """
|
bgneal@75
|
2 Models for the forums application.
|
bgneal@75
|
3 """
|
bgneal@75
|
4 from django.db import models
|
bgneal@75
|
5 from django.contrib.auth.models import User, Group
|
bgneal@75
|
6 from django.template.loader import render_to_string
|
bgneal@75
|
7
|
bgneal@75
|
8
|
bgneal@75
|
9 class Category(models.Model):
|
bgneal@75
|
10 name = models.CharField(max_length=80)
|
bgneal@75
|
11 slug = models.SlugField(max_length=80)
|
bgneal@75
|
12 position = models.IntegerField(blank=True, default=0)
|
bgneal@75
|
13 groups = models.ManyToManyField(Group, blank=True, null=True,
|
bgneal@75
|
14 help_text="If groups are assigned to this category, only members" \
|
bgneal@75
|
15 " of those groups can view this category.")
|
bgneal@75
|
16
|
bgneal@75
|
17 class Meta:
|
bgneal@75
|
18 ordering = ('position', )
|
bgneal@75
|
19 verbose_name_plural = 'Categories'
|
bgneal@75
|
20
|
bgneal@75
|
21 def __unicode__(self):
|
bgneal@75
|
22 return self.name
|
bgneal@75
|
23
|
bgneal@75
|
24
|
bgneal@75
|
25 class Forum(models.Model):
|
bgneal@75
|
26 category = models.ForeignKey(Category, related_name='forums')
|
bgneal@75
|
27 name = models.CharField(max_length=80)
|
bgneal@75
|
28 slug = models.SlugField(max_length=80)
|
bgneal@75
|
29 description = models.TextField(blank=True, default='')
|
bgneal@75
|
30 position = models.IntegerField(blank=True, default=0)
|
bgneal@75
|
31 moderators = models.ManyToManyField(Group, blank=True, null=True)
|
bgneal@75
|
32
|
bgneal@75
|
33 # denormalized fields to reduce database hits
|
bgneal@75
|
34 topic_count = models.IntegerField(blank=True, default=0)
|
bgneal@75
|
35 post_count = models.IntegerField(blank=True, default=0)
|
bgneal@75
|
36 last_post = models.OneToOneField('Post', blank=True, null=True,
|
bgneal@75
|
37 related_name='parent_forum')
|
bgneal@75
|
38
|
bgneal@75
|
39 class Meta:
|
bgneal@75
|
40 ordering = ('position', )
|
bgneal@75
|
41
|
bgneal@75
|
42 def __unicode__(self):
|
bgneal@75
|
43 return self.name
|
bgneal@75
|
44
|
bgneal@81
|
45 @models.permalink
|
bgneal@81
|
46 def get_absolute_url(self):
|
bgneal@81
|
47 return ('forums-forum_index', [self.slug])
|
bgneal@81
|
48
|
bgneal@75
|
49 def topic_count_update(self):
|
bgneal@75
|
50 """Call to notify the forum that its topic count has been updated."""
|
bgneal@75
|
51 self.topic_count = Topic.objects.filter(forum=self).count()
|
bgneal@75
|
52
|
bgneal@75
|
53 def post_count_update(self):
|
bgneal@75
|
54 """Call to notify the forum that its post count has been updated."""
|
bgneal@75
|
55 my_posts = Post.objects.filter(topic__forum=self)
|
bgneal@75
|
56 self.post_count = my_posts.count()
|
bgneal@75
|
57 if self.post_count > 0:
|
bgneal@75
|
58 self.last_post = my_posts[self.post_count - 1]
|
bgneal@75
|
59 else:
|
bgneal@75
|
60 self.last_post = None
|
bgneal@75
|
61
|
bgneal@75
|
62
|
bgneal@75
|
63 class Topic(models.Model):
|
bgneal@75
|
64 forum = models.ForeignKey(Forum, related_name='topics')
|
bgneal@75
|
65 name = models.CharField(max_length=255)
|
bgneal@75
|
66 creation_date = models.DateTimeField(auto_now_add=True)
|
bgneal@75
|
67 user = models.ForeignKey(User)
|
bgneal@75
|
68 view_count = models.IntegerField(blank=True, default=0)
|
bgneal@75
|
69 sticky = models.BooleanField(blank=True, default=False)
|
bgneal@75
|
70 locked = models.BooleanField(blank=True, default=False)
|
bgneal@75
|
71
|
bgneal@75
|
72 # denormalized fields to reduce database hits
|
bgneal@75
|
73 post_count = models.IntegerField(blank=True, default=0)
|
bgneal@75
|
74 update_date = models.DateTimeField(auto_now=True)
|
bgneal@75
|
75 last_post = models.OneToOneField('Post', blank=True, null=True,
|
bgneal@75
|
76 related_name='parent_topic')
|
bgneal@75
|
77
|
bgneal@75
|
78 class Meta:
|
bgneal@75
|
79 ordering = ('-sticky', '-update_date', )
|
bgneal@75
|
80
|
bgneal@75
|
81 def __unicode__(self):
|
bgneal@75
|
82 return self.name
|
bgneal@75
|
83
|
bgneal@82
|
84 @models.permalink
|
bgneal@82
|
85 def get_absolute_url(self):
|
bgneal@82
|
86 return ('forums-topic_index', [self.pk])
|
bgneal@82
|
87
|
bgneal@75
|
88 def post_count_update(self):
|
bgneal@75
|
89 """
|
bgneal@75
|
90 Call this function to notify the topic instance that its post count
|
bgneal@75
|
91 has changed.
|
bgneal@75
|
92 """
|
bgneal@75
|
93 my_posts = Post.objects.filter(topic=self)
|
bgneal@75
|
94 self.post_count = my_posts.count()
|
bgneal@75
|
95 if self.post_count > 0:
|
bgneal@75
|
96 self.last_post = my_posts[self.post_count - 1]
|
bgneal@75
|
97 self.update_date = self.last_post.creation_date
|
bgneal@75
|
98 else:
|
bgneal@75
|
99 self.last_post = None
|
bgneal@75
|
100 self.update_date = self.creation_date
|
bgneal@75
|
101
|
bgneal@83
|
102 def reply_count(self):
|
bgneal@83
|
103 """
|
bgneal@83
|
104 Returns the number of replies to a topic. The first post
|
bgneal@83
|
105 doesn't count as a reply.
|
bgneal@83
|
106 """
|
bgneal@83
|
107 if self.post_count > 1:
|
bgneal@83
|
108 return self.post_count - 1
|
bgneal@83
|
109 return 0
|
bgneal@83
|
110
|
bgneal@75
|
111
|
bgneal@75
|
112 class Post(models.Model):
|
bgneal@75
|
113 topic = models.ForeignKey(Topic, related_name='posts')
|
bgneal@75
|
114 user = models.ForeignKey(User, related_name='posts')
|
bgneal@75
|
115 creation_date = models.DateTimeField(auto_now_add=True)
|
bgneal@75
|
116 update_date = models.DateTimeField(auto_now=True)
|
bgneal@75
|
117 body = models.TextField()
|
bgneal@75
|
118 html = models.TextField()
|
bgneal@83
|
119 user_ip = models.IPAddressField(blank=True, default='', null=True)
|
bgneal@75
|
120
|
bgneal@75
|
121 class Meta:
|
bgneal@97
|
122 ordering = ('creation_date', )
|
bgneal@75
|
123
|
bgneal@91
|
124 @models.permalink
|
bgneal@91
|
125 def get_absolute_url(self):
|
bgneal@91
|
126 return ('forums-goto_post', [self.pk])
|
bgneal@91
|
127
|
bgneal@75
|
128 def summary(self):
|
bgneal@75
|
129 LIMIT = 50
|
bgneal@75
|
130 if len(self.body) < LIMIT:
|
bgneal@75
|
131 return self.body
|
bgneal@75
|
132 return self.body[:LIMIT] + '...'
|
bgneal@75
|
133
|
bgneal@75
|
134 def __unicode__(self):
|
bgneal@75
|
135 return self.summary()
|
bgneal@75
|
136
|
bgneal@75
|
137 def save(self, *args, **kwargs):
|
bgneal@75
|
138 html = render_to_string('forums/post.html', {'data': self.body})
|
bgneal@75
|
139 self.html = html.strip()
|
bgneal@75
|
140 super(Post, self).save(*args, **kwargs)
|
bgneal@75
|
141
|
bgneal@75
|
142 def delete(self, *args, **kwargs):
|
bgneal@75
|
143 first_post_id = self.topic.posts.all()[0].id
|
bgneal@75
|
144 super(Post, self).delete(*args, **kwargs)
|
bgneal@75
|
145 if self.id == first_post_id:
|
bgneal@75
|
146 self.topic.delete()
|
bgneal@75
|
147
|
bgneal@98
|
148
|
bgneal@98
|
149 class FlaggedPost(models.Model):
|
bgneal@98
|
150 """This model represents a user flagging a post as inappropriate."""
|
bgneal@98
|
151 user = models.ForeignKey(User)
|
bgneal@98
|
152 post = models.ForeignKey(Post)
|
bgneal@98
|
153 flag_date = models.DateTimeField(auto_now_add=True)
|
bgneal@98
|
154
|
bgneal@98
|
155 def __unicode__(self):
|
bgneal@98
|
156 return u'Post ID %s flagged by %s' % (self.post.id, self.user.username)
|
bgneal@98
|
157
|
bgneal@98
|
158 class Meta:
|
bgneal@98
|
159 ordering = ('flag_date', )
|
bgneal@98
|
160
|
bgneal@98
|
161 def get_post_url(self):
|
bgneal@98
|
162 return '<a href="%s">Post</a>' % self.post.get_absolute_url()
|
bgneal@98
|
163 get_post_url.allow_tags = True
|
bgneal@98
|
164
|
bgneal@75
|
165 # TODO: A "read" table
|