Skip to content

Instantly share code, notes, and snippets.

@agusmakmun
Last active January 10, 2017 15:57
Show Gist options
  • Save agusmakmun/6607cbd13b7e6b06a0da97cd18b2ef22 to your computer and use it in GitHub Desktop.
Save agusmakmun/6607cbd13b7e6b06a0da97cd18b2ef22 to your computer and use it in GitHub Desktop.
Django Forum Notifications Concept
class Notification(TimeStampedModel):
sender = models.ForeignKey(User, related_name='sender_notification')
receiver = models.ForeignKey(User, related_name='receiver_notification')
content_type = models.ForeignKey(
ContentType, related_name='notification', on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
STATUS_CHOICES = (
('mention', _('Mention')),
('reply', _('Reply Comment')),
('first_comment', _('First Comment'))
)
status = models.CharField(
max_length=20, default='reply',
choices=STATUS_CHOICES
)
content_object = GenericForeignKey('content_type', 'object_id')
def __str__(self):
status = _('replied your comment')
if self.status == 'mention':
status = _('mentioned you')
elif self.status == 'first_comment':
status = _('posted comment')
return _('%(username)s %(status)s on %(content_object)s at %(time)s') % {
'username': self.user.username,
'status': status,
'content_object': self.content_object,
'created': self.created
}
def get_related_object(self):
"""
return the related object of content_type.
eg: <Thread: Holisticly grow synergistic best practices>
"""
# This should return an error: MultipleObjectsReturned
# return self.content_type.get_object_for_this_type()
# So, i handle it with this one:
model_class = self.content_type.model_class()
return model_class.objects.get(id=self.object_id)
def get_model_name(self):
"""
return lowercase of model name.
eg: `thread`, `comment`
"""
return self.get_related_object()._meta.model_name
class Meta:
verbose_name = _('Detail Notification')
verbose_name_plural = _('Notifications')
ordering = ['-created']
@login_required
def notifications_dashboard(request):
"""
dashboard view for all users logged in.
"""
numb_pages = 10
get_page = request.GET.get('page')
template_name = 'app_forum/private/dashboard_notifications.html'
notifications = Notification.objects.filter(receiver=request.user) # here we got it by `receiver`
page_obj = PaginatorFBV(
notifications, numb_pages, get_page
).queryset_paginated()
page_range = PaginatorFBV(
notifications, numb_pages, get_page
).page_numbering()
notifications = page_obj.object_list
context = {
'notifications': notifications,
'page_obj': page_obj,
'page_range': page_range
}
return render(request, template_name, context)
@login_required
def thread_new(request, topic_slug):
"""
new thread form view.
:param `topic_slug` is slug for `Topic`
"""
template_name = 'app_forum/private/thread_new.html'
topic = get_object_or_404(Topic, slug=topic_slug)
if request.method == 'POST':
form = ThreadForm(request.POST, instance=Thread())
if form.is_valid():
initial = form.save(commit=False)
initial.author = request.user
# condition to set `type` of thread, `normal/pinned`
is_allowed = new_thread_privilege(request.user)
if is_allowed:
initial.type = request.POST.get('type')
else:
initial.type = 'normal'
initial.topic = topic
initial.save()
form.save()
# find mentions on this thread description
# and create a notification for users mentioned.
username_list = mention_finder(initial.description) # return list of `usernames`
for username in username_list:
if username != request.user.username:
# creating a `Notification` for the users
# that mentioned on this thread.
content_type = ContentType.objects.get(model='thread')
notification = Notification.objects.create(
sender=request.user,
receiver=get_object_or_404(User, username=username),
content_type=content_type,
object_id=initial.id,
status='mention'
)
notification.save()
return redirect('detail_thread_page',
topic_slug=topic.slug,
pk=initial.pk)
else:
form = ThreadForm(instance=Thread())
context = {'form': form, 'topic': topic}
return render(request, template_name, context)
@login_required
def thread_edit(request, topic_slug, pk):
"""
edit thread form view.
:param `topic_slug` is topic slug.
:param `pk` is pk/id from the thread.
"""
template_name = 'app_forum/private/thread_edit.html'
thread = get_object_or_404(
Thread, topic__slug=topic_slug, pk=pk)
# Find exited users that already mentioned before.
# return list of `usernames`
users_mentioned = mention_finder(thread.description)
# makesure the thread is allowed to be edit.
is_allowed = edit_thread_privilege(
thread=thread, user=request.user)
if is_allowed == False:
return redirect('detail_thread_page',
topic_slug=topic_slug, pk=pk)
if request.method == 'POST':
form = ThreadForm(request.POST, instance=thread)
if form.is_valid():
initial = form.save(commit=False)
initial.author = thread.author
initial.save()
form.save()
# find mentions on this thread description
# and create a notification for users mentioned.
# But, makesure the users doesn't exist at the notifications before.
# `users_mentioned` is list users already mentioned before.
username_list = mention_finder(initial.description)
for username in username_list:
if username not in users_mentioned and username != thread.author.username:
# creating a `Notification` for the users
# that mentioned on this thread.
content_type = ContentType.objects.get(model='thread')
notification = Notification.objects.create(
sender=thread.author,
receiver=get_object_or_404(User, username=username),
content_type=content_type,
object_id=thread.id,
status='mention'
)
notification.save()
return redirect('detail_thread_page',
topic_slug=topic_slug, pk=pk)
else:
form = ThreadForm(instance=thread)
context = {'form': form, 'thread': thread}
return render(request, template_name, context)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment