comparison gpp/forums/models.py @ 100:eb9f99382476

Forums: groups support. Some experimentation with select_related() to reduce queries. There are more opportunities for this, see the TODO comments in views.py.
author Brian Neal <bgneal@gmail.com>
date Tue, 15 Sep 2009 03:15:20 +0000
parents d0d779dd0832
children e67c4dd98db5
comparison
equal deleted inserted replaced
99:10d6182b9f6e 100:eb9f99382476
1 """ 1 """
2 Models for the forums application. 2 Models for the forums application.
3 """ 3 """
4 from django.db import models 4 from django.db import models
5 from django.db.models import Q
5 from django.contrib.auth.models import User, Group 6 from django.contrib.auth.models import User, Group
6 from django.template.loader import render_to_string 7 from django.template.loader import render_to_string
7 8
8 9
9 class Category(models.Model): 10 class Category(models.Model):
11 """
12 Forums belong to a category, whose access may be assigned to groups.
13 """
10 name = models.CharField(max_length=80) 14 name = models.CharField(max_length=80)
11 slug = models.SlugField(max_length=80) 15 slug = models.SlugField(max_length=80)
12 position = models.IntegerField(blank=True, default=0) 16 position = models.IntegerField(blank=True, default=0)
13 groups = models.ManyToManyField(Group, blank=True, null=True, 17 groups = models.ManyToManyField(Group, blank=True, null=True,
14 help_text="If groups are assigned to this category, only members" \ 18 help_text="If groups are assigned to this category, only members" \
19 verbose_name_plural = 'Categories' 23 verbose_name_plural = 'Categories'
20 24
21 def __unicode__(self): 25 def __unicode__(self):
22 return self.name 26 return self.name
23 27
28 def can_access(self, user):
29 """
30 Checks to see if the given user has permission to access
31 this category.
32 If this category has no groups assigned to it, return true.
33 Else, return true if the user belongs to a group that has been
34 assigned to this category, and false otherwise.
35 """
36 if self.groups.count() == 0:
37 return True
38 if user.is_authenticated():
39 return self.groups.filter(user__pk=user.id).count() > 0
40 return False
41
42
43 class ForumManager(models.Manager):
44 """
45 The manager for the Forum model. Provides a centralized place to
46 put commonly used and useful queries.
47 """
48
49 def forums_for_user(self, user):
50 """
51 Returns a queryset containing the forums that the given user can
52 "see" due to authenticated status, superuser status and group membership.
53 """
54 if user.is_superuser:
55 qs = self.all()
56 else:
57 user_groups = []
58 if user.is_authenticated():
59 user_groups = user.groups.all()
60
61 qs = self.filter(Q(category__groups__isnull=True) | \
62 Q(category__groups__in=user_groups))
63
64 return qs.select_related('category', 'last_post', 'last_post__user')
65
24 66
25 class Forum(models.Model): 67 class Forum(models.Model):
68 """
69 A forum is a collection of topics.
70 """
26 category = models.ForeignKey(Category, related_name='forums') 71 category = models.ForeignKey(Category, related_name='forums')
27 name = models.CharField(max_length=80) 72 name = models.CharField(max_length=80)
28 slug = models.SlugField(max_length=80) 73 slug = models.SlugField(max_length=80)
29 description = models.TextField(blank=True, default='') 74 description = models.TextField(blank=True, default='')
30 position = models.IntegerField(blank=True, default=0) 75 position = models.IntegerField(blank=True, default=0)
33 # denormalized fields to reduce database hits 78 # denormalized fields to reduce database hits
34 topic_count = models.IntegerField(blank=True, default=0) 79 topic_count = models.IntegerField(blank=True, default=0)
35 post_count = models.IntegerField(blank=True, default=0) 80 post_count = models.IntegerField(blank=True, default=0)
36 last_post = models.OneToOneField('Post', blank=True, null=True, 81 last_post = models.OneToOneField('Post', blank=True, null=True,
37 related_name='parent_forum') 82 related_name='parent_forum')
83
84 objects = ForumManager()
38 85
39 class Meta: 86 class Meta:
40 ordering = ('position', ) 87 ordering = ('position', )
41 88
42 def __unicode__(self): 89 def __unicode__(self):
59 else: 106 else:
60 self.last_post = None 107 self.last_post = None
61 108
62 109
63 class Topic(models.Model): 110 class Topic(models.Model):
111 """
112 A topic is a thread of discussion, consisting of a series of posts.
113 """
64 forum = models.ForeignKey(Forum, related_name='topics') 114 forum = models.ForeignKey(Forum, related_name='topics')
65 name = models.CharField(max_length=255) 115 name = models.CharField(max_length=255)
66 creation_date = models.DateTimeField(auto_now_add=True) 116 creation_date = models.DateTimeField(auto_now_add=True)
67 user = models.ForeignKey(User) 117 user = models.ForeignKey(User)
68 view_count = models.IntegerField(blank=True, default=0) 118 view_count = models.IntegerField(blank=True, default=0)
108 return self.post_count - 1 158 return self.post_count - 1
109 return 0 159 return 0
110 160
111 161
112 class Post(models.Model): 162 class Post(models.Model):
163 """
164 A post is an instance of a user's single contribution to a topic.
165 """
113 topic = models.ForeignKey(Topic, related_name='posts') 166 topic = models.ForeignKey(Topic, related_name='posts')
114 user = models.ForeignKey(User, related_name='posts') 167 user = models.ForeignKey(User, related_name='posts')
115 creation_date = models.DateTimeField(auto_now_add=True) 168 creation_date = models.DateTimeField(auto_now_add=True)
116 update_date = models.DateTimeField(auto_now=True) 169 update_date = models.DateTimeField(auto_now=True)
117 body = models.TextField() 170 body = models.TextField()