class Forum(models.Model): """ A Forum, containing Topics. It can be public or restricted to some groups. """ class Meta: verbose_name = 'Forum' verbose_name_plural = 'Forums' ordering = ['position_in_category', 'title'] title = models.CharField('Titre', max_length=80) subtitle = models.CharField('Sous-titre', max_length=200) # Groups authorized to read this forum. If no group is defined, the forum is public (and anyone can read it). group = models.ManyToManyField( Group, verbose_name='Groupe autorisés (Aucun = public)', blank=True) category = models.ForeignKey(Category, db_index=True, verbose_name='Catégorie') position_in_category = models.IntegerField('Position dans la catégorie', null=True, blank=True, db_index=True) slug = models.SlugField(max_length=80, unique=True) objects = ForumManager() def __str__(self): return self.title def get_absolute_url(self): return reverse('forum-topics-list', kwargs={'cat_slug': self.category.slug, 'forum_slug': self.slug}) def get_topic_count(self): """Retrieve or agregate the number of threads in this forum. If this number already exists, it must be stored \ in thread_count. Otherwise it will process a SQL query :return: the number of threads in the forum. """ try: return self.thread_count except AttributeError: return Topic.objects.filter(forum=self).count() def get_post_count(self): """Retrieve or agregate the number of posts in this forum. If this number already exists, it must be stored \ in post_count. Otherwise it will process a SQL query :return: the number of posts for a forum. """ try: return self.post_count except AttributeError: return Post.objects.filter(topic__forum=self).count() def get_last_message(self): """ :return: the last message on the forum, if there are any. """ try: return Post.objects.filter(topic__forum=self).order_by('-pubdate').all()[0] except IndexError: return None def can_read(self, user): """ Checks if an user can read current forum. The forum can be read if: - The forum has no access restriction (= no group), or - the user is in our database and is part of the restricted group which is needed to access this forum :param user: the user to check the rights :return: `True` if the user can read this forum, `False` otherwise. """ if self.group.count() == 0: return True else: # authentication is the best way to be sure groups are available in the user object if user is not None: groups = list(user.groups.all()) if not isinstance(user, AnonymousUser) else [] return Forum.objects.filter( group__in=groups, pk=self.pk).exists() else: return False
class Forum(models.Model): """ A Forum, containing Topics. It can be public or restricted to some groups. """ class Meta: verbose_name = "Forum" verbose_name_plural = "Forums" ordering = ["position_in_category", "title"] title = models.CharField("Titre", max_length=80) subtitle = models.CharField("Sous-titre", max_length=200) # Groups authorized to read this forum. If no group is defined, the forum is public (and anyone can read it). groups = models.ManyToManyField( Group, verbose_name="Groupes autorisés (aucun = public)", blank=True) # better handling of on_delete with SET(value)? category = models.ForeignKey(ForumCategory, db_index=True, verbose_name="Catégorie", on_delete=models.CASCADE) position_in_category = models.IntegerField("Position dans la catégorie", null=True, blank=True, db_index=True) slug = models.SlugField(max_length=80, unique=True) _nb_group = None objects = ForumManager() def __str__(self): return self.title def get_absolute_url(self): return reverse("forum-topics-list", kwargs={ "cat_slug": self.category.slug, "forum_slug": self.slug }) def get_topic_count(self): """Retrieve or aggregate the number of threads in this forum. If this number already exists, it must be stored \ in thread_count. Otherwise it will process a SQL query. :return: the number of threads in the forum. """ try: return self.thread_count except AttributeError: return Topic.objects.filter(forum=self).count() def get_post_count(self): """Retrieve or aggregate the number of posts in this forum. If this number already exists, it must be stored \ in post_count. Otherwise it will process a SQL query. :return: the number of posts for a forum. """ try: return self.post_count except AttributeError: return Post.objects.filter(topic__forum=self).count() def get_last_message(self): """ :return: the last message on the forum, if there are any. """ try: return Post.objects.filter( topic__forum=self).order_by("-pubdate").all()[0] except IndexError: return None def can_read(self, user): """ Checks if a user can read current forum. The forum can be read if: - The forum has no access restriction (= no group), or - the user is in our database and is part of the restricted group which is needed to access this forum :param user: the user to check the rights :return: `True` if the user can read this forum, `False` otherwise. """ if not self.has_group: return True else: # authentication is the best way to be sure groups are available in the user object if user is not None: groups = list(user.groups.all()) if not isinstance( user, AnonymousUser) else [] return Forum.objects.filter(groups__in=groups, pk=self.pk).exists() else: return False @property def has_group(self): """ Checks if this forum belongs to at least one group :return: ``True`` if it belongs to at least one group :rtype: bool """ if self._nb_group is None: self._nb_group = self.groups.count() return self._nb_group > 0