django-disqus 설치 및 사용법 (Disqus vs. LiveRe)


파이썬/장고 | 2019-01-17 02:01 | comments | 14,381 views


안녕하세요.

핀코인입니다.

핀코인의 댓글은 소셜 댓글 시스템 Disqus를 이용합니다.

1. 왜 댓글 시스템을 직접 구현하지 않는가.

댓글 시스템을 직접 구현하는 것은 생각보다 매우 복잡합니다.

  • 스레드형 게시물 (트리 자료구조)과 페이지네이션
  • 작성/수정 권한 관리
  • 댓글 작성 및 파일 업로드, @ 기호 사람 찾기 등을 위한 ajax 지원
  • 스팸 필터링 및 욕설/비속어 관리 등

위와 같이 고려할 요소가 매우 많습니다. 내부적으로 트리 자료구조는 django-mptt를 이용해서 쉽게 구현할 수 있다고 하지만 페이지네이션에 ajax 처리를 하다보면 배보다 배꼽이 더 커집니다.

댓글은 관리자 시스템도 준비가 되어야 하는데 이게 다 직접 구현하려면 신경 쓸 일이 꽤나 많습니다.

구현의 편리함은 있지만 소셜 댓글 시스템을 사용할 경우에는 회원 정보가 이원화되고 이질적인 사용자 경험을 제공합니다. 따라서 클리앙, 뽐뿌, 루리웹 같은 커뮤니티 사이트를 구축한다면 댓글 시스템을 직접 구현하는 것이 옳습니다. 반면에 블로그나 제품 구매후기의 경우에는 댓글 작성을 위한 지속적인 방문이 이뤄지지 않기 때문에 소셜 댓글 시스템을 사용해도 괜찮겠다는 결론을 내렸습니다.

2. Disqus vs. LiveRe

핀코인은 댓글 시스템을 직접 구현하는 것 대신에 소셜 댓글 시스템 Disqus를 이용합니다.

국산 소셜 댓글 솔루션으로 LiveRe가 있습니다. 그래서 LiveRe의 가장 큰 특징은 네이버/카카오톡 로그인 댓글을 지원한다는 점입니다. 그러나 무료 플랜으로 사용할 경우에는 광고가 있고 REST API 지원이 많이 부족합니다.

LiveRe 유료 플랜을 결제하는 것도 고려해서 직접 문의해봤으나 서비스 가격이 솔직히 좀 터무니 없이 비쌉니다. 가급적이면 국산 솔루션 LiveRe를 쓰려고 했지만 너무 비싼 가격 때문에 포기했습니다.

Disqus도 네이버/카카오톡 로그인을 지원하지 않고 댓글 관리 시스템이 많이 불편하지만 그래도 다양한 REST API를 지원하기 때문에 사용하기로 결정했습니다.

3. django-disqus 설치

disqus의 설치는 자바스크립트만 포함하면 되기 때문에 어떤 웹 페이지를 사용하더라도 구현이 복잡하지 않습니다. 그러나 좀 더 편리하게 템플릿 태그를 쓸 수 있도록 해주는 django-disqus를 설치했습니다.

django-disqus 공식 문서 매뉴얼: https://django-disqus.readthedocs.io/en/latest/

django-disqus 패키지는 아래와 같이 쉽게 설치할 수 있습니다.

pip install django-disqus

이제 settings.py 파일에 disqus 앱을 등록하고 아래와 같이 변수 값을 지정합니다.

INSTALLED_APPS += [
    'django.contrib.sites',
    'disqus',
]

SITE_ID = 1

DISQUS_API_SECRET = Secret.DISQUS_API_SECRET
DISQUS_API_KEY = Secret.DISQUS_API_KEY
DISQUS_WEBSITE_SHORTNAME = Secret.DISQUS_WEBSITE_SHORTNAME

매뉴얼에서는 DISQUS_API_KEY, DISQUS_WEBSITE_SHORTNAME 두 가지 값만 설명하고 있습니다. 저희는 나중에 Disqus 서버에 REST API 요청을 위해서 DISQUS_API_SECRET 값을 선언해두도록 하겠습니다.

https://disqus.com/api/applications/ 경로에서 위와 같이 Secret KeyPublic Key를 확인할 수 있습니다. DISQUS_API_KEYPublic Key를 지정하고 DISQUS_SECRET_KEYSecret Key를 지정합니다. django-disqus에서 변수명을 DISQUS_PUBLIC_KEY가 아닌 DISQUS_API_KEY로 선언했으므로 변수 이름에 주의합니다.

DISQUS_WEBSITE_SHORTNAME 역시 Disqus 가입 시 부여 받습니다. https://shortname.disqus.com/admin/settings/general/ 형태로 관리자 설정 화면에 접속할 수 있는데 이 때 shortname 하위 도메인이 여러분의 shortname이며 아래 화면과 같이 확인할 수 있습니다.

SITE_ID 값은 1로 하는데 이는 우리가 django.contrib.sites 앱을 설치하고 처음으로 레코드를 추가하면 PK가 1이기 때문입니다. 만약에 이 PK값을 변경하면 그에 맞춰서 수정해줘야 합니다.

django.contrib.sites 앱은 모델 선언이 있어서 반드시 데이터베이스 마이그레이션까지 완료해야 합니다.

python manage.py migrate

저희는 secret.py 모듈 안에 Secret 클래스를 만들고 여러 가지 비밀번호를 관리합니다. 그리고 .gitignore 같은 파일에 이 모듈을 등록해서 GitHub 같은 소스 코드 저장소에는 절대로 커밋되지 않도록 주의해야 합니다.

Site 모델의 도메인을 실제 서비스하는 도메인 이름과 일치하도록 설정해야 합니다. Django의 어드민에서 쉽게 설정할 수 있습니다만 아래와 같이 CLI 명령행으로 처리할 수도 있습니다.

>>> from django.contrib.sites.models import Site
>>> Site.objects.all()
[<Site: example.org>]
>>> s = Site.objects.all()[0]
>>> s.domain = 'www.pincoin.co.kr
>>> s.name = 'www.pincoin.co.kr'
>>> s.save()
>>> Site.objects.all()
  [<Site: www.pincoin.co.kr>]

만약 www 같은 하위 도메인이 있는 경우 이를 포함하여 도메인 주소를 지정합니다.

4. 댓글 목록 및 입력 폼

보통 댓글은 페이지의 본문 내용 하단에 위치합니다. 하단에 아래와 같이 태그를 넣어주면 간단하게 댓글 목록이 보이고 댓글을 입력할 수 있는 폼이 만들어집니다.

{% load disqus_tags %}
{% set_disqus_url post_absolute_url %}
{% disqus_show_comments %}

disqus_show_comments 템플릿 태그만 갖다 붙여주면 되니까 구현이 너무나 쉽습니다.

그런데 만약 댓글을 다는 본문 페이지(게시물 등)가 페이지네이션을 쓰고 있다거나 네이버 CPC 광고에서 여러 가지 태깅 정보를 GET 파라미터로 붙여서 넘겨줄 경우 커다란 문제가 발생합니다.

바로 아래와 같은 경우에 같은 블로그 게시물이지만 Disqus는 서로 다른 페이지로 간주합니다. 블로그 게시물이 늘어나고 ?page=1, ?page=2 GET 파라미터가 바뀌면 이전 댓글이 사라지는 것입니다. 진짜 문제는 Disqus 관리 페이지에서 댓글 스레드가 너무 많아서 관리 자체가 안 되는 상황이 됩니다.

위 예시의 경우 Query String 문자열을 무시하고 몇 번째 페이지가 되든간에 정확히 http://www.example.com/blog/www/posts/19/yet-another-post URL이 댓글 본문 페이지의 기준이 되도록 해야 합니다.

그것이 바로 {% set_disqus_url post_absolute_url %} 코드입니다.

그런데 문제는 템플릿 변수 post_absolute_url 값을 뷰에서 만들어 줘야 하는 것입니다. 예를 들어서 클래스형 뷰를 사용한다면 아마도 아래와 비슷한 코드가 될 것입니다.

    def get_context_data(self, **kwargs):
        context['post_absolute_url'] = self.request.build_absolute_uri(
            reverse('blog:post-detail', args=(self.object.blog.slug,
                                              self.object.pk,
                                              self.object.slug)))
        return context

프로토콜, 도메인을 포함한 완전한 절대 주소를 만들어서 Disqus에 넘겨줘야 하기 때문에 build_absolute_uri를 사용합니다.

5. 댓글 링크(anchor)

보통 댓글을 달 수 있는 본문 페이지의 위에는 글쓴이, 글쓴시각 같은 정보와 함께 댓글 개수를 함께 보여줍니다. 그리고 이것을 클릭하면 하단의 댓글 있는 곳으로 내려갑니다.

이것을 구현하는 a 링크 태그를 만들어 봅시다.

<a href="{{ post.get_absolute_url }}#disqus_thread">{% disqus_num_replies %} 댓글</a>

위와 같이 작성하면 django-disqus 템플릿이 알아서 ajax로 댓글 문자열을 댓글 개수로 표시해줍니다.

그런데 id 값은 반드시 #disqus_thread로 선언해야 합니다. 이는 Disqus 댓글 시스템에서의 약속으로 #comments 이렇게 임의적으로 선언할 경우에는 올바르게 동작하지 않습니다. 그리고 당연히 하단에 {% disqus_show_comments %} 템플릿 태그를 감싸는 <div> 태그에는 id="disqus_thread" 이렇게 속성을 부여해야 합니다.

6. 최신 댓글 목록

핀코인 블로그의 오른편 사이드바에 있는 최신 댓글 목록은 아래와 같이 템플릿 태그를 사용하면 됩니다.

{% load disqus_tags %}
{% disqus_recent_comments shortname 10 50 1 %}

먼저 템플릿을 불러오고 disqus_recent_comments 템플릿 태그를 사용합니다.

주요 옵션에 대한 설명은 공식 문서에 따르면 다음과 같습니다.

  • shortname: 어차피 settings.DISQUS_WEBSITE_SHORTNAME이 덮어 쓰므로 무시
  • num_items: 댓글 개수(10)
  • excerpt_length: 댓글 문자열 길이(50)
  • hide_avatars: 아바타 표시 안함(1)
  • avatar_size: 아바타를 표시할 경우 아바타 크기(기본값 32x32,,정사각형이므로 정수 하나 32)

다음 포스팅에서는 본문 페이지에 댓글 개수 필드를 추가하고 이를 주기적으로 업데이트하는 요령을 알아보도록 하겠습니다.

핀코인 쇼핑몰/블로그에 방문해주시는 여러분께서 남겨주시는 댓글이 큰 힘이 됩니다.

대한민국 1등 온라인 상품권 쇼핑몰 핀코인!

감사합니다.


#Django #Disqus


Related Posts

blog comments powered by Disqus