View should retain the notifications list when their state is changed

I am working on a simple notification system.
Consider the models.py;

class Notification(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    message = models.CharField(max_length=255)
    timestamp = models.DateTimeField(auto_now_add=True)
    is_read = models.BooleanField(default=False)

    def __str__(self):
        return self.message

From views.py, see the relevant views;

def Dashboard(request):
    donor_profile = Profile.objects.get(user=request.user)
    seeker=Seeker.objects.filter(b_group=donor_profile.b_group)

    if donor_profile.user.first_name and donor_profile.user.last_name and donor_profile.user.email and donor_profile.b_group and donor_profile.contact_number and donor_profile.image:
        profile_complete = True
    else :
        profile_complete = False
    
    # Get the count of unread notifications for the logged-in user
    unread_notification_count = Notification.objects.filter(user=request.user, is_read=False).count()

    # Fetch all notifications for the logged-in user
    notifications = Notification.objects.filter(user=request.user).order_by('-timestamp')

    minimum_date=timezone.now().strftime('%Y-%m-%d')
    maximum_date=(timezone.now()+datetime.timedelta(days=30)).strftime('%Y-%m-%d')

    context = {
        'donor_profile':donor_profile , 
        'profile_complete': profile_complete, 
        'notifications': notifications , 
        'unread_notification_count':unread_notification_count, 
        'seeker':seeker,
        'minimum_date':minimum_date,
        'maximum_date':maximum_date,
        }
    return render(request, 'Blood/dashboard.html', context)
@login_required
def mark_notification_as_read(request, notification_id):
    notifications = Notification.objects.get(id=notification_id)
    notifications.is_read = True
    notifications.save()

    return redirect('Blood:dashboard')

It is working but not as I expect. Hitting Mark as Read, do change the is_read state of a notification but it hides all the notifications from the template. The user has to click on the Notifications link again to see all the notifications.

What I want is that when a user hits Mark as Read, it should change the notification’s state but should not hide the notifications.

Please guide. Regards.

To help assist you with this, we’re going to need to know what they’re clicking on that triggers this mark_notification_as_read view, along with a verification that the URL named “Blood:dashboard” is the Dashboard view above.

We may also need to see the Blood/dashboard.html template.

Finally, we will need to know if this is all using regular Django or if you’re using some JavaScript on the front-end such as HTMX, jQuery, React, or some other library.

Ok. I am using only regular Django for this. Here are the paths in my urls.py;

app_name = 'Blood'

urlpatterns = [
    path('', views.Home, name='home'),  
    ...
    path('dashboard/', views.Dashboard, name='dashboard'), # Dashboard View shared above
    
    path('mark_notification_as_read/<int:notification_id>/', views.mark_notification_as_read, name='mark_notification_as_read'),

    path('del_notification/<int:notification_id>/', views.del_notification, name='del_notification'),
]

The problem under discussion is also with the del_notification view; Here it is;

@login_required
def del_notification(request, notification_id):
    notifications = Notification.objects.get(id=notification_id)
    notifications.delete()

    # Fetch all notifications so that all notifications appear again --/\/\q
    notifications = Notification.objects.filter(user=request.user).order_by('-timestamp')
    return render(request, 'Blood/dashboard.html', {'notifications': notifications})

This is the complete Blood/dashboard.html;

{% extends "Blood/index.html" %}
{% block content %}
    <br>
    <br>
    <br>
    <br>
    <div class="container2">
        <div class="sidebar">
            <ul>
                <li><a href="#" onclick="loadContent('donate')">Donate</a></li>
                <li><a href="#" onclick="loadContent('blood-request')">Post a Blood Request</a></li>
                {% if not profile_complete %}
                <li><a href="#" onclick="loadContent('complete-profile')">Complete Your Profile</a></li>
                {% endif %}
                <li><a href="#" onclick="loadContent('edit-profile')">Edit Profile</a></li>
                <li><a href="#" onclick="loadContent('notifications')">Notifications</a></li>
                <li><a href="#" onclick="loadContent('settings')"> Settings</a></li>
                <li><a href="#" onclick="loadContent('change-password')">Change Password</a></li>
                <li><a href="{% url "account_logout" %}" onclick="logout()">Logout</a></li>
            </ul>
        </div>
        <div class="content" id="content">
            <!-- Content will be loaded here -->
            
        </div>
    </div>
  
    
    <script>
        function loadContent(page) {
            // Simulate loading content based on the page parameter
            const contentDiv = document.getElementById('content');
            switch (page) {
                case 'donate':
                    //Instead of single or double quote, use backtick for inserting html contents in multiline format
                    contentDiv.innerHTML = `
                    <div class="container" style="height: 850px; overflow-y: auto;">
                        <br>
                        {% if seeker %}
                        <h3 class="text-center">Requests for Blood Group {{donor_profile.b_group}}</h3>
                        <br>
                        <table class="table table-sm table-bordered ">
                          <tr class="table-secondary">
                            <th>S.No</th>
                            <th>Name</th>
                            <th>Contact No</th>
                            <th>Donate Before</th>
                            <th>Details</th>
                          </tr>
                          {% for i in seeker %}
                              <tr class="table-success">
                                <td>{{ forloop.counter }}</td>
                                <td>{{i.name}}</td>
                                <td>{{i.phone}}</td>
                                <td>{{i.date}}</td>
                                <td> <a href="/seekers_details/{{i.id}}/" class="btn btn-sm btn-outline-secondary">View</a></td>
                              </tr>
                              {% endfor %}
                        </table>
                        {% else %}
                        <h2>No Blood Requests</h2>
                        {% endif %}
                    </div>`;
                    break;
                case 'blood-request':
                    // 15 April Code
                    contentDiv.innerHTML = `<div class="container">
                        <h3><i style="font-weight: bold;">Request For Blood</i></h3>
                        <form method="POST" action="{% url "Blood:seeker_request" %}"> {% csrf_token %}
                    <div class="row mt-4">
                        <div class="form-group col-md-12">
                            <label><i style="font-weight: bold;">Full Name</i></label>
                            <input type="text" class="form-control" name="name" id="name" placeholder="Enter Name" required>
                        </div>
                    </div>
                    
                    <div class="row mt-1">
                        <div class="form-group col-md-6">
                            <label><i style="font-weight: bold;">Email ID</i></label>
                            <input type="email" class="form-control" name="email" id="email" placeholder="Enter Email ID" required>
                        </div>
                        <div class="form-group col-md-6">
                            <label><i style="font-weight: bold;">Contact Number</i></label>
                            <input type="number" class="form-control" name="phone" id="phone" placeholder="Enter Contact Number" required>
                        </div>
                    </div>
                    <div class="row mt-1">
                        <div class="form-group col-md-6">
                            <label><i style="font-weight: bold;">Blood Group</i></label>
                            <select class="form-control" name="b_group" required>
                                <option>A+</option>
                                <option>A-</option>
                                <option>B+</option>
                                <option>B-</option>
                                <option>AB+</option>
                                <option>AB-</option>
                                <option>O+</option>
                                <option>O-</option>
                                </select>
                        </div>
                            <div class="form-group col-md-6">
                                <label><i style="font-weight: bold;">Date Of Donation</i></label>
                                <input type="date" class="form-control" id="date" name="date" min="{{minimum_date}}" max="{{maximum_date}}" required>
                            </div>
                    </div>
                    <button type="submit" class="btn btn-primary" onclick="showAlert('Blood request submitted Successfully')">Submit</button>
                    </form>
                    </div>`;
                    break;
                case 'notifications':
                    contentDiv.innerHTML = `
                    <div class="container" style="height: 850px; overflow-y: auto;">
                        <br>
                        {% if notifications %}
                        <h3 class="text-center">Your Notifications</h3>
                        <br>
                        <table class="table table-sm table-bordered">
                          <tr class="table-secondary">
                            <th>S.No</th>
                            <th>Notifications</th>
                            <th>Actions</th>
                          </tr>
                          {% for notification in notifications %}
                              <tr class="table-success">
                                <td  class="text-center">{{ forloop.counter }}</td>
                                <td>{{ notification.message }}. <b> {{ notification.timestamp}} </b> </td>
                                {% if notification.is_read %}
                                <td>
                                    <a href="/del_notification/{{notification.id}}" class="btn btn-sm btn-outline-secondary"> Delete</a>
                                    <span style="margin: 0 1px;"></span> 
                                    <a href="/seekers_details/{{i.id}}/" class="btn btn-sm btn-outline-secondary">Details</a>
                                </td>
                                {% else %}
                                <td>
                                    <a href="/mark_notification_as_read/{{ notification.id }}" class="btn btn-sm btn-outline-secondary">Mark as Read</a>
                                    <span style="margin: 0 1px;"></span> 
                                    <a href="/del_notification/{{ notification.id }}" class="btn btn-sm btn-outline-secondary">Delete</a>
                                    <span style="margin: 0 1px;"></span> 
                                    <a href="/seekers_details/{{ notification.blood_request_id }}/" class="btn btn-sm btn-outline-secondary">Details</a>
                                </td>
                                
                                {% endif %}
                              </tr>
                              {% endfor %}
                        </table>
                        {% else %}
                        <h3 class="text-center">You have no Notifications</h3>
                        {% endif %}
                    </div>`
                    break;
                case 'complete-profile':
                    // 15 April Code
                    contentDiv.innerHTML = `<div class="container">
                        <h3>Complete Your Profile</h3>
                        <form method="POST" action="{% url "Blood:edit_profile" %}" enctype="multipart/form-data"> {% csrf_token %}
                            <div class="row mt-4">
                                <div class="form-group col-md-12">
                                    <label><i style="font-weight: bold;">Username</i></label>
                                    <input type="text" class="form-control" name="username" id="username" value="{{user}}" readonly>
                                </div>
                            </div>
                    
                            <div class="row mt-1">
                                <div class="form-group col-md-6">
                                    <label><i style="font-weight: bold;">First Name</i></label>
                                    <input type="text" class="form-control" name="f_name" id="first_name"
                                        value="{{request.user.first_name}}">
                                </div>
                    
                                <div class="form-group col-md-6">
                                    <label><i style="font-weight: bold;">Last Name</i></label>
                                    <input type="text" class="form-control" name="l_name" id="last_name" value="{{request.user.last_name}}">
                                </div>
                            </div>
                    
                            <div class="row mt-1">
                                <div class="form-group col-md-6">
                                    <label><i style="font-weight: bold;">Email ID</i></label>
                                    <input type="email" class="form-control" name="email" id="email" value="{{request.user.email}}">
                                </div>
                                <div class="form-group col-md-6">
                                    <label><i style="font-weight: bold;">Contact Number</i></label>
                                    <input type="number" class="form-control" name="c_info" id="phone"
                                        value="{{donor_profile.contact_number}}">
                                </div>
                            </div>
                    
                    
                            <div class="row mt-2">
                                <div class="form-group col-md-6">
                                    <label><i style="font-weight: bold;">Blood Group</i></label>
                                    <select class="form-control" name="b_group">
                                        <option>{{donor_profile.b_group}}</option>
                                        <option>A+</option>
                                        <option>A-</option>
                                        <option>B+</option>
                                        <option>B-</option>
                                        <option>AB+</option>
                                        <option>AB-</option>
                                        <option>O+</option>
                                        <option>O-</option>
                                    </select>
                                </div>
                                <div class="form-group col-md-6">
                                    <label><i style="font-weight: bold;">Profile Photo</i></label>
                                    <input type="file" class="form-control" id="image" name="image">
                                </div>
                            </div>
                    
                            <br>
                    
                            <button type="submit" class="btn btn-primary" onclick="showAlert('Profile Completed Successfully')">Submit</button>
                        </form>
                    </div>`;
                    break;
                case 'edit-profile':
                    // 17 April Code
                    contentDiv.innerHTML = `<div class="container">
                    <h3>Edit Profile</h3>
                    <form method="POST" action="{% url "Blood:edit_profile" %}" enctype="multipart/form-data"> {% csrf_token %}
                        <div class="row mt-4">
                            <div class="form-group col-md-12">
                                <label><i style="font-weight: bold;">Username</i></label>
                                <input type="text" class="form-control" name="username" id="username" value="{{user}}" readonly>
                            </div>
                        </div>
                
                        <div class="row mt-1">
                            <div class="form-group col-md-6">
                                <label><i style="font-weight: bold;">First Name</i></label>
                                <input type="text" class="form-control" name="f_name" id="first_name"
                                    value="{{request.user.first_name}}">
                            </div>
                
                            <div class="form-group col-md-6">
                                <label><i style="font-weight: bold;">Last Name</i></label>
                                <input type="text" class="form-control" name="l_name" id="last_name" value="{{request.user.last_name}}">
                            </div>
                        </div>
                
                        <div class="row mt-1">
                            <div class="form-group col-md-6">
                                <label><i style="font-weight: bold;">Email ID</i></label>
                                <input type="email" class="form-control" name="email" id="email" value="{{request.user.email}}">
                            </div>
                            <div class="form-group col-md-6">
                                <label><i style="font-weight: bold;">Contact Number</i></label>
                                <input type="number" class="form-control" name="c_info" id="phone"
                                    value="{{donor_profile.contact_number}}">
                            </div>
                        </div>
                
                
                        <div class="row mt-2">
                            <div class="form-group col-md-6">
                                <label><i style="font-weight: bold;">Blood Group</i></label>
                                <select class="form-control" name="b_group">
                                    <option>{{donor_profile.b_group}}</option>
                                    <option>A+</option>
                                    <option>A-</option>
                                    <option>B+</option>
                                    <option>B-</option>
                                    <option>AB+</option>
                                    <option>AB-</option>
                                    <option>O+</option>
                                    <option>O-</option>
                                </select>
                            </div>
                            <div class="form-group col-md-6">
                                <label><i style="font-weight: bold;">Profile Photo</i></label>
                                <input type="file" class="form-control" id="image" name="image">
                            </div>
                        </div>
                
                        <br>
                
                        <button type="submit" class="btn btn-primary" onclick="showAlert('Profile Updated Successfully')">Submit</button>
                    </form>
                    </div>`;
                    break;
                case 'change-password':
                    contentDiv.innerHTML = '<iframe src="{% url 'account_change_password' %}" frameborder="0" width="100%" height="100%"></iframe>';
                    break;
                case 'settings':
                    // New case for the 'settings' link
                    contentDiv.innerHTML = `
                        <div class="container">
                            <h3>Settings</h3>
                            <form method="POST" action="{% url "Blood:save_settings" %}"> 
                                {% csrf_token %}
                                <div class="form-group">
                                    <label class="switch">
                                        <input type="checkbox" name="get_notifications" checked id="get_notifications">
                                        <span class="slider round"></span>
                                    </label>
                                    <label><i style="font-weight: bold;"> Send me Blood Request Notifications (RECOMMENDED)</i></label>
                                </div>
                                <br>
                                <button type="submit" class="btn btn-primary" onclick="showAlert('Your preferences have been saved successfully')">Save</button>
                            </form>
                        </div>`;
                break;
                default:
                    contentDiv.innerHTML = '<h2>Dashboard</h2><p>Welcome to your Dashboard!</p>';
            }
        }

        function logout() {
            // Implement logout functionality
            alert('Logout successful');
            // Redirect to logout page or clear session, etc.
        }

        // 15 April code 
        function showAlert(message) {
            // JavaScript code to handle alert message after form submission
            alert(message);
        }
    </script>
    <br>    
    {% endblock %}

From the Blood/dashboard.html, below is the exact markup that shows where the user clicks to delete or mark notifications;

                          {% for notification in notifications %}
                              <tr class="table-success">
                                <td  class="text-center">{{ forloop.counter }}</td>
                                <td>{{ notification.message }}. <b> {{ notification.timestamp}} </b> </td>
                                {% if notification.is_read %}
                                <td>
                                    <a href="/del_notification/{{notification.id}}" class="btn btn-sm btn-outline-secondary"> Delete</a>
                                    <span style="margin: 0 1px;"></span> 
                                    <a href="/seekers_details/{{i.id}}/" class="btn btn-sm btn-outline-secondary">Details</a>
                                </td>
                                {% else %}
                                <td>
                                    <a href="/mark_notification_as_read/{{ notification.id }}" class="btn btn-sm btn-outline-secondary">Mark as Read</a>
                                    <span style="margin: 0 1px;"></span> 
                                    <a href="/del_notification/{{ notification.id }}" class="btn btn-sm btn-outline-secondary">Delete</a>
                                    <span style="margin: 0 1px;"></span> 
                                    <a href="/seekers_details/{{ notification.blood_request_id }}/" class="btn btn-sm btn-outline-secondary">Details</a>
                                </td>
                                
                                {% endif %}
                              </tr>
                              {% endfor %}

Actually, you’re not. You are using JavaScript to update the page - you’re just not using an established library for doing this.

One of the issues here is that you’re mixing what happens in the server (template rendering) with what happens out in the browser (running JavaScript)

Those template tags you have in your JavaScript function get rendered when the page is being rendered - they do not get sent out to the browser. (If you examine the HTML that is present in the browser, you’ll see this.)

You either need to render the html in the server, or you need to use JavaScript in the browser for your loops and conditions in what you’re trying to produce - you can’t mix them both together like this.

It works when you refresh the page, because you’re giving the server a chance to rerender that page with the current data.

Thanks KenWhitesell

Please pinpoint which statement of the JavaScript causes page update

and which one is the established library for doing this?

Dashboard.html contains only 3 JavaScript functions;

  1. loadContent() - only simulates the loading of a pages, in reality it only displays the contents in designated
  2. logout() - it only displays an alert before going to {% url “account_logout” %} link
  3. showAlert() - it only displays appropriate alerts before submitting the forms, the form however submits.
    Correct me if I am wrong in interpreting any of these functions. I am still unable to figure out how these JavaScript functions interfere with the server-side. Deleting the notifications or setting them read/unread is carried out by Django views ultimately.

Inside the JavaScript, I have never used template tags. Elaborate please.

I am sorry but I think I will need some example to understand this.

Thank you again for bearing with me. I understand that you have responded with the needed explanation and guidance but I think, I am even below the beginner’s level here that is hindering to get it.

If you are not understanding the JavaScript that you are trying to use here, then that would be your first step. I suggest you find some suitable JavaScript tutorials and documentation to help you gain the understanding of this code that you will need to understand what it’s doing.

(I’m sorry, but I don’t have any recommendations in that area.)

Here is how I resolved it by simply not getting my hands dirty with JavaScript for the time being; Instead of using my loadContent() JavaScript function, I used a Bootstrap’s navigation bar, with simple path entries in urls.py, related views in views.py and templates for all the separate links in the navigation bar.