Skip to content
Advertisement

How can i implement Notifications system in django

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'),

Advertisement

Answer

Here is an outline for a basic notification system in Django:

Model

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)

Creating a notification

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)

List of notifications

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.

Showing new notifications to users

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>

Real life example

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

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement