Guest User

Untitled

a guest
Jan 26th, 2020
164
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.70 KB | None | 0 0
  1. class AbstractPost(DatedModel):
  2.     """ Represents a forum post. A forum post is always linked to a topic. """
  3.  
  4.     topic = models.ForeignKey(
  5.         'forum_conversation.Topic', related_name='posts', on_delete=models.CASCADE,
  6.         verbose_name=_('Topic'),
  7.     )
  8.     poster = models.ForeignKey(
  9.         settings.AUTH_USER_MODEL, related_name='posts',
  10.         blank=True, null=True, on_delete=models.CASCADE, verbose_name=_('Poster'),
  11.     )
  12.     anonymous_key = models.CharField(
  13.         max_length=100, blank=True, null=True, verbose_name=_('Anonymous user forum key'),
  14.     )
  15.  
  16.     # Each post can have its own subject. The subject of the thread corresponds to the
  17.     # one associated with the first post
  18.     subject = models.CharField(verbose_name=_('Subject'), max_length=255)
  19.  
  20.     # Content
  21.     content = MarkupTextField(
  22.         validators=[
  23.             validators.NullableMaxLengthValidator(machina_settings.POST_CONTENT_MAX_LENGTH),
  24.         ],
  25.         verbose_name=_('Content'),
  26.     )
  27.  
  28.     # Username: if the user creating a topic post is not authenticated, he must enter a username
  29.     username = models.CharField(max_length=155, blank=True, null=True, verbose_name=_('Username'))
  30.  
  31.     # A post can be approved before publishing ; defaults to True
  32.     approved = models.BooleanField(default=True, db_index=True, verbose_name=_('Approved'))
  33.  
  34.     # The user can choose if they want to display their signature with the content of the post
  35.     enable_signature = models.BooleanField(
  36.         default=True, db_index=True, verbose_name=_('Attach a signature'),
  37.     )
  38.  
  39.     # A post can be edited for several reason (eg. moderation) ; the reason why it has been
  40.     # updated can be specified
  41.     update_reason = models.CharField(
  42.         max_length=255, blank=True, null=True, verbose_name=_('Update reason'),
  43.     )
  44.  
  45.     # Tracking data
  46.     updated_by = models.ForeignKey(
  47.         settings.AUTH_USER_MODEL, editable=False, blank=True, null=True, on_delete=models.SET_NULL,
  48.         verbose_name=_('Lastly updated by'),
  49.     )
  50.     updates_count = models.PositiveIntegerField(
  51.         editable=False, blank=True, default=0, verbose_name=_('Updates count'),
  52.     )
  53.  
  54.     objects = models.Manager()
  55.     approved_objects = ApprovedManager()
  56.  
  57.     if settings.MACHINA_SEARCH_ENGINE == 'postgres': # для постгрес-поиска нужно создать специальные поля
  58.         from django.contrib.postgres.search import SearchVectorField
  59.         content_search = SearchVectorField(null=True)
  60.  
  61.     class Meta:
  62.         abstract = True
  63.         app_label = 'forum_conversation'
  64.         ordering = ['created', ]
  65.         get_latest_by = 'created'
  66.         verbose_name = _('Post')
  67.         verbose_name_plural = _('Posts')
  68.  
  69.         if settings.MACHINA_SEARCH_ENGINE == 'postgres': # индексируем спец-поля в постгресе
  70.             from django.contrib.postgres.indexes import GinIndex
  71.             indexes = [ GinIndex(name='content_index', fields=["content_search"]) ]
  72.  
  73.     def __str__(self):
  74.         return self.subject
  75.  
  76.     @property
  77.     def is_topic_head(self):
  78.         """ Returns ``True`` if the post is the first post of the topic. """
  79.         return self.topic.first_post.id == self.id if self.topic.first_post else False
  80.  
  81.     @property
  82.     def is_topic_tail(self):
  83.         """ Returns ``True`` if the post is the last post of the topic. """
  84.         return self.topic.last_post.id == self.id if self.topic.last_post else False
  85.  
  86.     @property
  87.     def is_alone(self):
  88.         """ Returns ``True`` if the post is the only single post of the topic. """
  89.         return self.topic.posts.count() == 1
  90.  
  91.     @property
  92.     def position(self):
  93.         """ Returns an integer corresponding to the position of the post in the topic. """
  94.         position = self.topic.posts.filter(Q(created__lt=self.created) | Q(id=self.id)).count()
  95.         return position
  96.  
  97.     def clean(self):
  98.         """ Validates the post instance. """
  99.         super().clean()
  100.  
  101.         # At least a poster (user) or a session key must be associated with
  102.         # the post.
  103.         if self.poster is None and self.anonymous_key is None:
  104.             raise ValidationError(
  105.                 _('A user id or an anonymous key must be associated with a post.'),
  106.             )
  107.         if self.poster and self.anonymous_key:
  108.             raise ValidationError(
  109.                 _('A user id or an anonymous key must be associated with a post, but not both.'),
  110.             )
  111.  
  112.         if self.anonymous_key and not self.username:
  113.             raise ValidationError(_('A username must be specified if the poster is anonymous'))
  114.  
  115.     def save(self, *args, **kwargs):
  116.         """ Saves the post instance. """
  117.         new_post = self.pk is None
  118.         super().save(*args, **kwargs)
  119.  
  120.         # Ensures that the subject of the thread corresponds to the one associated
  121.         # with the first post. Do the same with the 'approved' flag.
  122.         if (new_post and self.topic.first_post is None) or self.is_topic_head:
  123.             if self.subject != self.topic.subject or self.approved != self.topic.approved:
  124.                 self.topic.subject = self.subject
  125.                 self.topic.approved = self.approved
  126.  
  127.         # Trigger the topic-level trackers update
  128.         self.topic.update_trackers()
  129.  
  130.     def delete(self, using=None):
  131.         """ Deletes the post instance. """
  132.         if self.is_alone:
  133.             # The default way of operating is to trigger the deletion of the associated topic
  134.             # only if the considered post is the only post embedded in the topic
  135.             self.topic.delete()
  136.         else:
  137.             super(AbstractPost, self).delete(using)
  138.             self.topic.update_trackers()
Advertisement
Add Comment
Please, Sign In to add comment