I created an app where user's can post a question and get answers from others users. Now I want to implement a notification system, so that when a user answer a question, the author of that question will receive notification. Like social media notifications.
The home templates:
<div class="container">
<div class="row justify-content-center">
<div class="row justify-content-center">
<div class="col-md-6">
<a href="{% url 'question' %}" class="btn btn-primary m-1">Ask Question</a>
<a href="{% url 'notification' %}" class="btn btn-primary m-1">Notifications</a>
<a href="{% url 'FeedBack' %}" class="btn btn-primary m-1">FeedBack</a>
<a href="{% url 'login' %}" class="btn btn-primary m-1">Log Out</a>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row justify-content-center">
{% for question in list_of_question reversed %}
<div class="col-md-4">
<div class="card my-3">
<div class="card-header">
<p class="card-title">{{question.user.username.upper}}</p>
</div>
<div class="card-body">
<a href="{% url 'view-Question' question.id %}" style="text-decoration: none;">
<p class="card-title">{{question.title}}</p>
</a>
<p>Category: {{question.category}}</p>
</div>
</div>
</div>
{%endfor%}
</div>
</div>
the models:
class Question(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=100, blank=False, null=False)
body = RichTextField(blank=False, null=False)
category = models.CharField(max_length=50, blank=False, null=False)
def __str__(self):
return str(self.title)
class Answer(models.Model):
user = models.ForeignKey(User, blank=False, null=False, on_delete=models.CASCADE)
answer = RichTextField(blank=False, null=False)
post = models.ForeignKey(Question, blank=False, null=False, on_delete=models.CASCADE)
def __str__(self):
return str(self.user)
The views:
class My_Question(LoginRequiredMixin, CreateView):
model = Question
fields = ['title', 'body', 'category']
template_name = 'question.html'
success_url = reverse_lazy('index')
def form_valid(self, form):
form.instance.user = self.request.user
return super (My_Question, self).form_valid(form)
class My_Answer(LoginRequiredMixin, CreateView):
model = Answer
fields = ['answer']
template_name = 'answer.html'
success_url = reverse_lazy('index')
def form_valid(self, form):
form.instance.user = self.request.user
form.instance.post_id = self.kwargs['pk']
return super (My_Answer, self).form_valid(form)
def viewQuestion(request, pk):
question = Question.objects.get(id=pk)
answers = Answer.objects.filter(post_id=question)
context = {'question':question, 'answers':answers}
return render(request, 'viewQuestion.html', context)
the home page view:
@login_required(login_url='login')
def index(request):
query = request.GET.get('q', None)
list_of_question = Question.objects.all()
if query is not None:
list_of_question = Question.objects.filter(
Q(title__icontains=query) |
Q(category__icontains=query)
)
context = {'list_of_question':list_of_question}
return render(request, 'index.html', context)
the urls
path('index/', views.index, name='index'),
path('view/<int:pk>/', views.viewQuestion, name='view-Question'),
path('question/<int:pk>/answer/', views.My_Answer.as_view(),
name='answer'),
path('question/', views.My_Question.as_view(), name='question'),
Here is an outline for a basic notification system in Django:
You need a model to store notifications. Each notification belongs to a user and has content (i.e. a text message). You also need to store whether a message has been read and a timestamp:
class Notification(models.Model):
is_read = models.BooleanField(default=False)
message = models.TextField()
timestamp = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
You can then create a new notification for a user when needed, e.g. when another user answers a question you can also create a notification for the question's owner in the view.
class My_Answer(LoginRequiredMixin, CreateView):
...
def form_valid(self, form):
...
form.instance.user = self.request.user
question_author = form.instance.post.user
Notification.objects.create(user=question_author, text="New answer!")
...
return super().form_valid(form)
Then you need a page that lists all notifications for the current user. That can be implemented with a standard list view.
The query would look something like this:
class NotificationListView(ListView):
model = Notification
def get_queryset(self):
return Notifications.objects.filter(user=self.request.user).order_by("-timestamp")
You of course also need to define a URL and a template for this new view. We will define the URL name as notifications
.
Finally, you need to inform users about new notifications. This can be done by checking how many unread notifications the current user has and showing a badge on the web badge. This would be part of the index view.
@login_required(login_url='login')
def index(request):
...
unread_notifications = Notification.objects.filter(user=request.user, is_read=False).count()
context["unread_notifications"] = unread_notifications
...
Then on your home page you need a link to a page that shows all notifications and a badge that shows how many unread notifications the current user has. Something like this:
<a href="{% url "notifications" %}">
Notifications
{% if unread_notifications %}
<span class="badge bg-secondary">{{ unread_notifications }}</span>
{% endif %}
</a>
If you want to see how this is implemented in a real project, here is the link to an open source project called "Alliance Auth" that implements a portal web page and has a very similar notification architecture. The link is to the notification app within that portal: https://gitlab.com/allianceauth/allianceauth/-/tree/master/allianceauth/notifications