如何在Angular 4中结合Django后端使用django-notifications处理通知?
Got it, let's break down how to make these two tools play nicely together. The core issue here is that Angular 4 runs as a separate frontend layer with its own template system—it can't natively parse the raw HTML/JS snippets from the django-notifications package. Instead, we need to build a custom bridge between your Django backend (which stores and manages notifications) and your Angular frontend (which renders and interacts with them). Here's a step-by-step approach:
1. Expose Notification Data via a Django API
First, you need to make your django-notifications data accessible to Angular through a REST API. The easiest way to do this is with Django REST Framework (DRF):
Create a serializer for the
Notificationmodel to convert database objects to JSON:from rest_framework import serializers from notifications.models import Notification class NotificationSerializer(serializers.ModelSerializer): # Use StringRelatedField to get human-readable names instead of IDs actor = serializers.StringRelatedField() target = serializers.StringRelatedField() action_object = serializers.StringRelatedField() class Meta: model = Notification fields = ['id', 'actor', 'verb', 'target', 'action_object', 'timestamp', 'unread']Build API views to fetch unread notifications and mark them as read:
from rest_framework import generics from rest_framework.permissions import IsAuthenticated from notifications.models import Notification from .serializers import NotificationSerializer class UserUnreadNotifications(generics.ListAPIView): serializer_class = NotificationSerializer permission_classes = [IsAuthenticated] def get_queryset(self): # Return only unread notifications for the logged-in user return Notification.objects.unread().filter(recipient=self.request.user) class MarkNotificationAsRead(generics.UpdateAPIView): serializer_class = NotificationSerializer permission_classes = [IsAuthenticated] queryset = Notification.objects.all() def perform_update(self, serializer): # Use the built-in method from django-notifications to mark as read serializer.instance.mark_as_read()Map these views to URLs in your Django project's
urls.pyso Angular can reach them.
2. Create an Angular Notification Service
Next, build an Angular service to handle all communication with your Django API. This will encapsulate fetching notifications, marking them as read, etc.:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class NotificationService { // Adjust this to match your Django API's base URL private apiBaseUrl = '/api/notifications/'; constructor(private http: HttpClient) {} // Fetch all unread notifications for the current user getUnreadNotifications(): Observable<any[]> { return this.http.get<any[]>(`${this.apiBaseUrl}unread/`); } // Mark a specific notification as read markAsRead(notificationId: number): Observable<any> { return this.http.patch(`${this.apiBaseUrl}${notificationId}/mark-read/`, {}); } // Optional: Fetch all notifications (read + unread) getAllNotifications(): Observable<any[]> { return this.http.get<any[]>(`${this.apiBaseUrl}all/`); } }
Don't forget to add HttpClientModule to your Angular app's main module to enable HTTP requests!
3. Build the Angular Notification Component
Now create a component to display notifications and handle user interactions. Here's a basic, functional example:
Component TypeScript
import { Component, OnInit } from '@angular/core'; import { NotificationService } from './notification.service'; @Component({ selector: 'app-notifications', templateUrl: './notifications.component.html', styleUrls: ['./notifications.component.css'] }) export class NotificationsComponent implements OnInit { unreadNotifications: any[] = []; constructor(private notificationService: NotificationService) {} ngOnInit(): void { this.loadUnreadNotifications(); } loadUnreadNotifications(): void { this.notificationService.getUnreadNotifications().subscribe( (notifications) => { this.unreadNotifications = notifications; }, (error) => { console.error('Failed to load notifications:', error); } ); } markNotificationAsRead(notificationId: number): void { this.notificationService.markAsRead(notificationId).subscribe( () => { // Update the local list to remove the now-read notification this.unreadNotifications = this.unreadNotifications.filter(n => n.id !== notificationId); }, (error) => { console.error('Failed to mark notification as read:', error); } ); } }
Component Template
<div class="notifications-container"> <button class="notification-toggle"> Notifications <span *ngIf="unreadNotifications.length > 0" class="unread-badge">{{ unreadNotifications.length }}</span> </button> <div class="notification-dropdown" *ngIf="unreadNotifications.length > 0"> <div *ngFor="let notification of unreadNotifications" class="notification-item"> <p> <strong>{{ notification.actor }}</strong> {{ notification.verb }} {{ notification.target || notification.action_object }} </p> <small class="timestamp">{{ notification.timestamp | date:'short' }}</small> <button (click)="markNotificationAsRead(notification.id)" class="mark-read-btn">Mark as Read</button> </div> </div> <p *ngIf="unreadNotifications.length === 0" class="no-notifications">No unread notifications</p> </div>
Component CSS (Optional)
.notifications-container { position: relative; display: inline-block; } .notification-toggle { padding: 8px 16px; cursor: pointer; border: 1px solid #ddd; border-radius: 4px; } .unread-badge { background-color: #dc3545; color: white; border-radius: 50%; padding: 2px 6px; font-size: 12px; margin-left: 4px; } .notification-dropdown { position: absolute; top: 100%; right: 0; background: white; border: 1px solid #ddd; border-radius: 4px; min-width: 280px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); margin-top: 4px; } .notification-item { padding: 12px; border-bottom: 1px solid #eee; } .notification-item:last-child { border-bottom: none; } .timestamp { display: block; color: #666; font-size: 12px; margin: 4px 0; } .mark-read-btn { font-size: 12px; padding: 4px 8px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; } .no-notifications { padding: 12px; color: #666; font-size: 14px; }
4. Handle Authentication & CSRF
Since your Django API requires authenticated users, make sure Angular sends the necessary credentials:
- For session-based auth, add
withCredentials: trueto your HttpClient requests (or configure it globally via an interceptor). - For CSRF protection, create an Angular interceptor to automatically read the CSRF cookie set by Django and include it in the
X-CSRFTokenheader of your requests.
5. Optional: Real-Time Notifications
If you want notifications to appear in real-time without page reloads, integrate Django Channels with WebSockets. Use Angular's native WebSocket API or the rxjs/webSocket module to connect to your Django WebSocket endpoint and listen for new notifications as they're created.
内容的提问来源于stack exchange,提问作者Shoaib Iqbal

