imsaiful
imsaiful

Reputation: 1604

How to implement Notification view in django correctly?

I have implemented Django notification in my index view. But I have more view like create a view, update view delete view etc. When the user first login to my application, I show the number of notification and links but when the user switches to another view then number of notification changes to zero. Is there any way to retain all the notification in every view of Django. This is my views.py file

from django.shortcuts import render, redirect, render_to_response
from django.http import HttpResponse, HttpResponseRedirect
from django.views.generic.edit import FormMixin

from .models import Report_item, ClaimForm, UserNotification
from django.views import generic
from django.db.models import Q
from django.contrib.auth import login, authenticate
from django.shortcuts import render, redirect
from django.utils import timezone
from django.views.generic import View, UpdateView, DeleteView
from .forms import SignUpForm, LoginForm
from django.contrib.auth import logout

from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
from django.core.urlresolvers import reverse_lazy
from django.db.models import Q


def IndexView(request):
    if request.user.is_anonymous:
        print("Hello")
        query_list = Report_item.objects.all()
        query = request.GET.get('q')
        if query:
            query_list = query_list.filter(Q(title__icontains=query) |
                                           Q(item_type__icontains=query) |
                                           Q(city__icontains=query) |
                                           Q(Description__icontains=query)).distinct()
        context = {
            "object_list": query_list,
        }
        return render(request, "feed/index.html", context)
    else:
        query_list = Report_item.objects.all()
        query = request.GET.get('q')
        if query:
            query_list = query_list.filter(Q(title__icontains=query) |
                                           Q(item_type__icontains=query) |
                                           Q(city__icontains=query) |
                                           Q(location__icontains=query) |
                                           Q(Description__icontains=query)).distinct()

        n = UserNotification.objects.filter(user=request.user, viewed=False)
        context = {
            "object_list": query_list,
            'notification': n,
            'count': n.count(),
        }
        return render(request, "feed/index.html", context)


class SearchCtaegoryView(generic.ListView):
    template_name = "feed/index.html"

    def get_queryset(self):
        query_list = Report_item.objects.all()
        slug = self.kwargs.get("slug")
        if slug:
            query_list = query_list.filter(Q(category__icontains=slug) | Q(category__iexact=slug))
        return query_list


class ReportCreate(generic.CreateView):
    model = Report_item
    fields = ['title', 'item_type', 'location', 'city', 'image', 'Description']

    def form_valid(self, form):
        self.object = form.save(commit=False)
        self.object.owner = self.request.user
        self.object.save()
        return FormMixin.form_valid(self, form)


class ReportDetail(generic.DetailView):
    model = Report_item
    template_name = 'feed/detail.html'


class ClaimForm(generic.CreateView):
    model = ClaimForm
    fields = ['Your_name', 'Your_mobile_number', 'Detail_proof']


class SignUpForm(generic.CreateView):
    form_class = SignUpForm
    template_name = "feed/SignUp.html"

    def get(self, request):
        form = self.form_class(None)
        return render(request, self.template_name, {'form': form})

    def post(self, request):

        form = self.form_class(request.POST)
        if form.is_valid():
            print("form valid")
            user = form.save(commit=False)
            username = form.cleaned_data['username']
            password = form.cleaned_data['password1']
            user.set_password(password)
            form.save()
            user = authenticate(username=username, password=password)
            if user is not None:
                if user.is_active:
                    login(request, user)
                    return redirect('feed:index')
        else:
            print(form.errors)

        return render(request, self.template_name, {'form': form})


class LoginForm(generic.CreateView):
    print("login")
    form_class = LoginForm
    template_name = "feed/SignUp.html"

    def get(self, request):
        form = self.form_class(None)
        return render(request, self.template_name, {'form': form})

    def post(self, request):
        form = self.form_class(request.POST)
        if form.is_valid():
            UserModel = get_user_model()
            email = request.POST['email']
            password = request.POST['password']
            username = UserModel.objects.get(email=email)
            user = authenticate(request, username=username, password=password)
            if user is not None:
                if user.is_active:
                    login(request, user)
                    return redirect('')
        else:
            print(form.errors)


def logout_view(request):
    logout(request)
    query_list = Report_item.objects.all()
    return render(request, "feed/index.html", {'object_list': query_list})


def Profile(request, username):
    print(username)
    qs = Report_item.objects.filter(owner__username=username)
    context = {
        "object_list": qs,
    }
    return render(request, "feed/profile.html", context)


class ReportUpdate(UpdateView):
    model = Report_item
    fields = ['title', 'item_type', 'location', 'city', 'image', 'Description']


class ReportDelete(DeleteView):
    model = Report_item
    success_url = reverse_lazy('feed:index')


class RequestItem(generic.CreateView):
    model = UserNotification
    fields = ['Name', 'Mobile_No', 'Proof']

    def form_valid(self, form):
        print(self.kwargs)

        self.object = form.save(commit=False)
        qs = Report_item.objects.filter(id=self.kwargs.get("pk"))
        self.object.user = qs[0].owner
        self.object.save()
        return HttpResponse("<h1>Hello Friends </h1>")


def show_notification(request, notification_id):
    n = UserNotification.objects.get(id=notification_id)
    context = {
        "n": n,
    }
    n.viewed = True
    n.save()
    return render(request, "feed/notification.html", context)


def read_notification(request, notification_id):
    n = UserNotification.objects.get(id=notification_id)
    n.viewed = True
    n.save()
    return HttpResponse("<h1>Hello Friends chai pee lo</h1>")


def mynotification(request):
    n = UserNotification.objects.filter(user=request.user, viewed=False)
    print(type(n))
    return render_to_response("feed/loggedin.html",
                              {'full_name': request.user.first_name, 'notification': n, })


def read_Notification(request):
    n = UserNotification.objects.filter(user=request.user)
    print(type(n))
    return render_to_response("feed/loggedin.html",
                              {'full_name': request.user.first_name, 'notification': n, })

Upvotes: 0

Views: 2052

Answers (1)

little_birdie
little_birdie

Reputation: 5877

Fancy web sites use websockets/AJAX for this. But if you just want it to update on every page load, use a Django context processor.

A context processor is a function that runs every time any template is rendered.. and it doesn't matter which view is being accessed. The context processor can add additional template variables that are available in every template.

So, first write the function.. this function returns a dictionary containing object_list, notification, and count for the current user if they are logged in, or nothing if they are not.

def notification_context(request):
    # Most of the code below is simply copied from the question, it
    # would be different for different applications.  The important thing
    # is that we have to figure out the values to be placed in the template
    # context.

    # If the user is not logged in, we don't know who they are so we return an empty.
    # dictionary which results in nothing new being added to the template context.
    if request.user.is_anonymous:
        return {}

    # look up the notifications for the current user
    query_list = Report_item.objects.all()
    query = request.GET.get('q', None)
    if query:
        query_list = query_list.filter(
            Q(title__icontains=query) |
            Q(item_type__icontains=query) |
            Q(city__icontains=query) |
            Q(location__icontains=query) | 
            Q(Description__icontains=query)
        ).distinct()

    n = UserNotification.objects.filter(user=request.user, viewed=False)

    # The return value must be a dict, and any values in that dict
    # are added to the template context for all templates.        
    # You might want to use more unique names here, to avoid having these
    # variables clash with variables added by a view.  For example, `count` could easily
    # be used elsewhere.
    return {
        'object_list': query_list,
        'notification': n,
        'count': n.count(),
    }

Now tell django to use this processor. In your settings.py, find the TEMPLATES section, and under OPTIONS, you'll see context_processors. Add yours, eg:

TEMPLATES = [{
    'OPTIONS': {
        'context_processors': [
            'django.template.context_processors.debug',
            'django.template.context_processors.request',
            'django.contrib.auth.context_processors.auth',
            'django.contrib.messages.context_processors.messages',
            # fill in the correct appname.  Also, normally context processor functions go in 
            # context_processors.py, but if you only have one then it doesn't matter much.
            'your_appname.views.notification_context',
        ],
    },
},]

And that's it! Now, when the user is logged in, you should get your variables in the template every time. And if you want your heading to be in every template with these variables displayed, you should place the heading in a master site template and then all your other templates should extend that one. That way, you don't duplicate your heading template code 100 times...

PS: I'll add one more suggestion. Rather than directly returning your variables, nest them to avoid cluttering up your template namespace. Like so:

return { 'notifications': {
        'object_list': query_list,
        'notification': n,
        'count': n.count(),
    }
}

Then, in your template, it will look like this:

{{ notifications.count }}
{{ notifications.query_list }}

Etc etc.. much nicer.

Upvotes: 5

Related Questions