django 기능 개발 :: Web Push Notification

phyyou·2020년 11월 12일
0
post-thumbnail

Web Push Notification이란?

W3C에서 제정한 Service Worker 표준을 통해 웹사이트에서도 Push Notification을 지원 할 수 있습니다. 웹사이트에 접속하지 않아도 브라우저가 실행 중이라면 Push Notification이 사용자에게 노출됩니다. Push Notification은 웹표준으로 IE를 제외한 Chrome, Firefox, Edge, Safari 등 최신 브라우저와 모바일 브라우저에서 지원하는 기술입니다. 여기에서는 django에서 웹 푸시 알람을 구현하는 방법을 저번 리팩토링에 이어 알아보겠습니다.

이 글에서 webpush를 실행시킬 때 signal을 활용하므로 이전 글을 읽고 오는 것을 추천드립니다.

django-webpush 라이브러리

설치 및 설정 작업

역시나 그 django답게 웹푸시도 라이브러리가 존재합니다.
pypi에서 설명을 보고 따라해 보겠습니다.

pip install django-webpush

을 통해 설치 하고, 설치되었으면 등록을 해야죠?

# settings.py
INSTALLED_APPS = (
    ...
    'webpush',
)

설정 이후로, 웹 푸시 알람을 위한 VAPID 키와 이메일을 설정해 주어야 합니다.
아래와 같이 설정해 줍시다.

# settings.py
WEBPUSH_SETTINGS = {
    "VAPID_PUBLIC_KEY": "Vapid Public Key",
    "VAPID_PRIVATE_KEY":"Vapid Private Key",
    "VAPID_ADMIN_EMAIL": "admin@example.com"
}

이제 이곳에 Vapid 키와 이메일을 등록해야 됩니다. 문서에서는 Vapid 키의 생성을web-push-codelab.glitch.me 를 통해 등록하는 것을 추천하지만, 사이트는 2020년 경으로 운영을 중단한 것으로 보입니다. 따라서 다른 생성 사이트를 구해야 하는데 저는 d3v.one이라는 사이트를 통해 생성하였습니다.

또한 이메일을 등록하는데 이는 딱히 상관은 없으나 보안을 위해 새로운 계정을 생성하는 것을 추천드립니다.

더욱 더 자세한 내용은 구글 공식 Web push notification을 참고해 봅시다.

그 이후 url을 등록해 webpush를 알람을 설정하는 url을 설정해줍시다.

urlpatterns =  [
    ...
    re_path(r'^webpush/', include('webpush.urls'))
]

또한 이 라이브러리는 jinja 템플릿을 지원한다고 하지만, 안쓰니 넘어가 줍시다.

모든 작업을 마치면 마이그레이트를 해줍시다. python manage.py migrate

템플릿을 통해 알림 등록 구현

{% load webpush_notifications %}으로 로드를 해주고
을 하고,
head 태그 사이에 {% webpush_header %}를 넣어주면 기본적으로 완료된다.
{% webpush_header %}에는 js파일을 로드 하는 기능인데, 개발중이면 상관이 없겠지만, 배포를 진행했다면, collectstatic으로 js파일을 등록해 주자.

이렇게 등록을 하고, 버튼을 넣어 주자.
{% webpush_button %}을 통해 넣을 수 있는데, 이때 class를 지정해서 넣을 수 있다.

{% webpush_button with_class="btn btn-outline-info" %}처럼 말이다.

bootstrap을 쓰는 사람에게는 아주 유용한 기능이다.

이렇게 등록을 해주었다면, 보내면 되는데, 이때 context에서 알림을 보내줄 그룹을 지정해 줄 수 있는데, 딱히 전체 사용자한테 보낼 나는 필요가 없다.

알림 보내기

보내는 것은 대체로 webpush에서 send_xxx_notification 을 통해 된다.
보낼 그룹이나, 사용자, 구독한 사용자, 이 3가지로 문서에서는 말하고 있으며, 나는 사이트에서 등록한 모든 사용자에게 보내는 것으로 하였기에 send_to_subscription 메소드를 사용하였다.

# webpush.py
from django.contrib.auth import get_user_model

from webpush import send_user_notification
from webpush.utils import send_to_subscription
from webpush import send_group_notification

import json # https://github.com/safwanrahman/django-webpush/issues/71

def episode_webpush(episode):

    User = get_user_model()
    users = User.objects.all()

    payload = {"head": f"{episode.__str__()}이 업데이트 되었습니다.", "body": f"{episode.__str__()} 업데이트 일시 : {episode.modify_date}", 
            "icon": "https://i.imgur.com/...", "url": f"{episode.get_absolute_url()}"}
     
    payload = json.dumps(payload) # json으로 변환 https://github.com/safwanrahman/django-webpush/issues/71

    for user in users:
        push_infos = user.webpush_info.select_related("subscription") 

        for push_info in push_infos:
            send_to_subscription(push_info.subscription, payload)

나는 View 함수에서 등록하지 않고 따로 webpush.py파일을 만들어 활용하였다.
그 이유는 View 함수에서 실행하는 것이아닌 전 글에서 signal을 이용하여 save 메소드가 실행 된 후 처리되는 것처럼 webpush 또한 지정한 모델의 save 메소드가 동작을 하면 webpush를 실행시키도록 하는 것이다.

그래서 Episode 객체를 인수로 받아서 활용하였다.

또한 중요한 이슈가 있는데 바로 json으로 딕셔너리를 변환해 주어야 하는 것이다. 이유는 이슈글을 읽어 보자.

from django.db.models.signals import post_save
from django.dispatch import receiver
from manga.models import Episode, Category
from django.db.models import F, Sum, Count, Case, When, Avg

from webpush import send_user_notification
from webpush import send_group_notification

from .webpush import episode_webpush

@receiver(post_save, sender = Episode)
def episode_post_save(sender, **kwargs ):
    category = kwargs['instance'].category
    category.modify_date = kwargs['instance'].modify_date
    category.save()
    episode_webpush(kwargs['instance'])

이렇게 post_save sender를 통해 글이 저장되면 알람이 가도록 하였다.

이 외에도 celery, view를 통해 동작시킬 수도 있다는 점을 활용해 보는것을 추천한다.

profile
박효영

0개의 댓글