📢 시작 🏷️
오늘은 소셜 미디어나 커뮤니티 사이트에서 사용자 경험을 향상시키는 기능중 하나인 알림 시스템을 구현하고자 합니다. 사용자들은 자신의 콘텐츠나 작게는 글, 댓글에 대한 반응을 실시간을 받기를 원합니다. 이 글에서는 데이터베이스 기반의 알림 시스템을 구축하여 이를 구현하고자 합니다.
📢 개요
구현할 알림 시스템은 다음 유형의 활동에 대해 알림을 생성합니다:
- 게시글에 대한 좋아요
- 게시글에 달린 댓글
- 댓글에 달린 대댓글
- 사용자 팔로우
📝 모델 정의
데이터베이스에 저장해야하므로 새롭게 app을 추가해야합니다.
from django.db import models
from django.contrib.auth import get_user_model
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
User = get_user_model()
class Notification(models.Model):
# 알림 유형
LIKE = 'like'
COMMENT = 'comment'
FOLLOW = 'follow'
MENTION = 'mention'
REPLY = 'reply'
NOTIFICATION_TYPES = (
(LIKE, '좋아요'),
(COMMENT, '댓글'),
(FOLLOW, '팔로우'),
(MENTION, '멘션'),
(REPLY, '답글'),
)
# 알림 받는 사용자
recipient = models.ForeignKey(User, on_delete=models.CASCADE, related_name='notifications')
# 알림 보낸 사용자
actor = models.ForeignKey(User, on_delete=models.CASCADE, related_name='actions')
# 알림 유형
notification_type = models.CharField(max_length=20, choices=NOTIFICATION_TYPES)
# 알림 관련 객체 (게시글, 댓글 등)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
# 알림 텍스트
text = models.CharField(max_length=255)
# 읽음 여부
is_read = models.BooleanField(default=False)
# 생성 시간
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-created_at']
def __str__(self):
return f"{self.actor} {self.get_notification_type_display()} to {self.recipient}"
✔️ GenericForeignKey : 다양한 유형의 객체(댓글, 글 등)를 참조합니다.
✔️ NOTIFICATION_TYPES : 알림 받고싶은 유형을 지정합니다.
📝 유틸 추가
from .models import Notification
from django.contrib.contenttypes.models import ContentType
def create_notification(recipient, actor, notification_type, content_object, text=None):
"""
알림 생성 함수
"""
# 자기 자신에게는 알림을 보내지 않음
if recipient == actor:
return None
content_type = ContentType.objects.get_for_model(content_object)
# 기본 텍스트 설정
if text is None:
if notification_type == Notification.LIKE:
text = f"{actor.nickname}님이 회원님의 게시글을 좋아합니다."
elif notification_type == Notification.COMMENT:
text = f"{actor.nickname}님이 회원님의 게시글에 댓글을 남겼습니다."
elif notification_type == Notification.FOLLOW:
text = f"{actor.nickname}님이 회원님을 팔로우합니다."
elif notification_type == Notification.MENTION:
text = f"{actor.nickname}님이 회원님을 언급했습니다."
elif notification_type == Notification.REPLY:
text = f"{actor.nickname}님이 회원님의 댓글에 답글을 남겼습니다."
notification = Notification.objects.create(
recipient=recipient,
actor=actor,
notification_type=notification_type,
content_type=content_type,
object_id=content_object.id,
text=text
)
return notification
🔍 views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from .models import Notification
@login_required
def notification_list(request):
"""알림 목록 보기"""
notifications = Notification.objects.filter(recipient=request.user)
unread_count = notifications.filter(is_read=False).count()
return render(request, 'notifications/notification_list.html', {
'notifications': notifications,
'unread_count': unread_count
})
@login_required
def mark_as_read(request, notification_id):
"""알림 읽음 표시"""
notification = get_object_or_404(Notification, id=notification_id, recipient=request.user)
notification.is_read = True
notification.save()
# 알림 클릭 시 해당 객체로 이동
content_object = notification.content_object
if notification.notification_type == Notification.LIKE or notification.notification_type == Notification.COMMENT:
# 게시글이나 댓글 관련 알림
if hasattr(content_object, 'post'):
# 댓글인 경우 게시글로 이동
return redirect('post_detail', post_id=content_object.post.id)
else:
# 게시글인 경우
return redirect('post_detail', post_id=content_object.id)
elif notification.notification_type == Notification.FOLLOW:
# 팔로우 알림은 해당 사용자 프로필로 이동
return redirect('profile')
# 기본적으로 알림 목록으로 리디렉션
return redirect('notifications:list')
@login_required
def mark_all_as_read(request):
"""모든 알림 읽음 표시"""
if request.method == 'POST':
notifications = Notification.objects.filter(recipient=request.user, is_read=False)
notifications.update(is_read=True)
return redirect('notifications:list')
🔍 이벤트 알림 추가
댓글, 팔로우, 좋아요의 view에 알림을 생성하도록 수정해야합니다. 일단은 팔로우에 대한 알림을 추가하였습니다.
@login_required
def follow_toggle(request, user_id):
"""사용자 팔로우/언팔로우 토글 기능"""
if request.method != 'POST':
return redirect('profile')
target_user = get_object_or_404(CustomUser, id=user_id)
# 자기 자신을 팔로우할 수 없음
if request.user == target_user:
messages.error(request, '자기 자신을 팔로우할 수 없습니다.')
return redirect('profile')
# 이미 팔로우 중인지 확인
follow_relation = Follow.objects.filter(follower=request.user, following=target_user)
if follow_relation.exists():
# 팔로우 관계가 있으면 삭제 (언팔로우)
follow_relation.delete()
messages.success(request, f'{target_user.nickname}님 팔로우를 취소했습니다.')
else:
# 팔로우 관계가 없으면 생성 (팔로우)
follow = Follow.objects.create(follower=request.user, following=target_user)
messages.success(request, f'{target_user.nickname}님을 팔로우합니다.')
# 팔로우 알림 생성
create_notification(
recipient=target_user,
actor=request.user,
notification_type=Notification.FOLLOW,
content_object=follow
)
# 이전 페이지로 리디렉션
return redirect(request.META.get('HTTP_REFERER', 'profile'))
🔍 컨텍스트 프로세서
모든 페이지에서 읽지 않은 알림수를 표시하기 위해 추가합니다.
def notifications_count(request):
if request.user.is_authenticated:
unread_count = request.user.notifications.filter(is_read=False).count()
return {'unread_notifications_count': unread_count}
return {'unread_notifications_count': 0}
settings.py에 등록합니다.
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
'DIRS': [os.path.join(BASE_DIR, 'templates')],
"APP_DIRS": True,
"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",
'messages_app.context_processors.unread_messages_count',
# 컨텍스트 프로세서서
'notifications.context_processors.notifications_count',
],
},
},
]
'Django 연습' 카테고리의 다른 글
| 18. Django와 BeautifulSoup을 이용한 웹 크롤링 (0) | 2025.04.11 |
|---|---|
| 16. Django 대댓글 기능 구현 (0) | 2025.04.01 |
| 14. Django 쪽지 기능 구현 (0) | 2025.03.19 |
| 13. Django 게시글 북마크 기능 (0) | 2025.03.12 |
| 12. Django 게시글 이미지 추가 (0) | 2025.03.11 |