Django 프레임워크로 RSS 피드 만들기

2020. 02. 23 IT/컴퓨터 > Django

블로그를 네이버 등 검색엔진에 등록하려면 RSS 피드를 제출하는 것이 좋다고 한다. 사실 예전부터 RSS라는 말은 많이 들어 봤지만 실제로 사용해본 적이 없고, 주변에서 RSS를 통해 구독하는 사람도 본 적이 없어서 어떤 것인지 개념이 모호한 상태였다. 새로 RSS 피드를 만들면서 간단히 공부해 보았다.

 

RSS는 Really Simple Syndication, 혹은 Rich Site Summary 의 약자라고 하는데, syndication은 또 뭔가? 전통적인 사전적 의미는 기사, 사진, 텔레비전 프로그램 등을 여러 신문사 등에 파는 행위를 syndication이라고 하는 것 같다. 요즘 주로 쓰이는 의미는 블로그등 웹사이트의 컨텐츠를 타겟 구독층에 노출시키는 것을 말한다.

 

Really Simple Syndication, 즉 자기 글을 아주 간단하게 사람들한테 배포할 수 있는 기술이라는건데..실제로 구동되는 방식은, 사이트에서 RSS 피드를 제공하면 경우 방문자가 관심있는 피드 주소들을 RSS 리더 등의 프로그램을 이용해서 등록해 둔다. 그러면 사이트에 새 글이 올라오는 경우 그 사이트들을 일일이 돌아다니지 않아도 RSS 리더 프로그램이 자동으로 새 글이 떴다는 것을 알려주게 된다. 그렇게 해서 구독자는 쉽게 여러 관심 사이트에 올라오는 새로운 컨텐츠를 확인할 수 있고, 반대로 매체 입장에서도 컨텐츠를 쉽게 사람들에게 전달하는 채널이 되는 것이다.

두번째 약자인 Rich Site Summary 라는 표현은 좀 더 기술적이고 직설적인 표현인데, 개념은 이전에 기술한 사이트맵 (sitemap.xml) 과 비슷한것같다. 사이트의 컨텐츠 내용을 요약해서 보여 주는 페이지라는 얘기다.

참고: Django sitemap 프레임워크를 이용해서 사이트맵 만들기

차이점은, 사이트맵은 간단히 제목과 링크 정도만 제공하는 대신 사이트 전체의 컨텐츠를 모두 요약해서 보여주는 것이 목적인 반면 RSS 피드는 전체 컨텐츠를 다 전달하는 것이 아니라 주로 최근에 발행된 컨텐츠를 모아서 전달해주는 것이라는 점이다. RSS 의 목적상 방문자가 사이트에 직접 들어오지 않아도 내용을 알 수 있어야 하므로 사이트맵처럼 제목 위주의 간단한 요약이 아니라, 글 본문과 첨부된 사진같은 해당 컨텐츠의 내용 전체를 제공해 주는것이 권장된다고 한다 (즉 풍부한 사이트 요약 = Rich Site Summary).

 

장고(Django) 프레임워크에는 간단하게 RSS 피드를 생성할 수 있는 syndication feed framework 라는 도구가 포함되어 있다. 이를 이용하면 RSS 와 Atom 피드를 쉽게 생성할 수 있다.

 

#1. 우선 models.py 에 다음과 같이 블로그 글을 정의하는 Post라는 모델이 이미 구성되어 있다.

[ models.py ]
class Post(models.Model):
    title = models.CharField(verbose_name='Title', max_length=40)
    content = RichTextUploadingField(verbose_name='Post Content')
    author = models.ForeignKey(User, null=False, on_delete=models.CASCADE)

(설명을 간략하게 하기 위해 기타 field 는 생략함)

 

#2. 이후 feeds.py 라는 파일을 새로 만들어 생성될 RSS feed 의 내용을 정의해 준다. 파일의 위치는 어디이든 상관 없지만, 가급적이면 models.py 와 같은 디렉토리에 만들어주는 것이 관리에 편할 것 같다.

[ feeds.py ]
from django.contrib.syndication.views import Feed
from django.urls import reverse
from blog.models import Post


class RecentPostsFeed(Feed):
    title = 'Recent posts from Windy Bay blog'
    link = '/feeds/'
    description = 'Updates on additions and changes to posts'

    def items(self):
        return Post.objects.filter(published_date__isnull=False).order_by('-published_date')[:10]

    def item_title(self, item):
        return item.title

    def item_description(self, item):
        return item.content

    def item_link(self, item):
        return reverse('blog:post_detail', args=[item.pk])

 

우선 Feed 클래스를 import 해 주고 그 클래스를 상속해 원하는 내용을 담을 feed 클래스를 정의해 주면 된다. models.py 에서 Post 클래스를 import 해 주어야 내용을 읽어올 수 있다. 

Feed 클래스에는 미리 정의된 속성이 있는데, 위에서 title, link, description 은 나중에 생성될 RSS feed의 <title>, <link>, <description> 에 보여지는 속성이므로 알맞게 작성하면 되겠다.

이후에 역시 Feed 클래스에 미리 정의된 메서드들을 정의하면 되는데, 우선 가장 기본적인 items() 에는 RSS에 표시할 글들을 Django Queryset 을 이용해서 읽어 오면 된다. 위의 코드는 이 블로그에 등록된 글 중 발행이 된 글만 찾아오도록 필터를 해 주고 그 중 최근 발행 일자 글 10개를 return 하도록 한 것인데, 필터가 필요 없는 경우에는

Post.objects.order_by('-published_date')[:10]

식으로 하면 될 것이다. Queryset 에서 데이터를 읽어오는 작업은 Django 작업을 하면서 가장 기본적인 내용 중 하나이니 관련된 내용을 나중에 정리해 보겠다.

이렇게 items()를 작성하고 나서, RSS feed에 표시해주고 싶은 내용들을 메서드를 이용해 정의해주면 된다. 위 코드의 item_title(), item_description(), item_link() 의 내용들이다. 참고로 이 메서드의 이름은 임의로 정한 것이 아니라 Feed 클래스 내에 이미 설정되어 있는 것들이다. item_link() 의 경우 해당 글로 바로 연결되는 URL 을 제공해주는 것이다.

 

#3. 그리고 나서 프로젝트 최상위의 urls.py 에 방금 작성한 feed를 연결할 수 있는 URL 을 매핑해준다.

[ urls.py ]
urlpatterns = [

    ...(기존 url들)...

    path('feeds/', RecentPostsFeed(), name='feeds'),
]

이렇게 하면 주소창에 windybay.net/feeds/ 를 입력했을때 RSS 피드가 보이게 된다.

 

여기까지 진행하면 RSS 리더 등에서 feed를 읽어들이는데 문제는 없다. 그런데 다른 사이트들의 경우 RSS feed 링크를 클릭하면 태그에 따라 깔끔하게 정리된 XML 포맷으로 보여지는데, 위의 방법으로 만든 feed 는 지저분하게 일반 text 파일처럼 아무 정리가 안 된 파일이 보이는 것이 문제이다. 예를 들어 아래와 같은 식으로..

 

그리고 파이어폭스 등 브라우저에 따라서는 feed의 내용이 보이는 것이 아니라 해당되는 파일을 다운로드 하는 창이 바로 열리는 등 불편한 점이 있다.

이것은 Django 가 자동으로 만들어주는 feed 의 기본 타입이 application/rss+xml 이라는 타입이라서 발생하는 문제라고 한다. 컨텐츠의 타입을 application/xml 로 지정해 주면 이런 문제가 해결된다. Django 에서 feed의 타입을 지정해주기 위해 준비해놓은 Class가 여러가지 있는데, 여기서는 DefaultFeed 클래스를 이용해 문제를 해결하면 된다. 

 

#4. 우선 위의 코드에 DefaultFeed를 임포트하는 문을 추가해주고, 이를 상속해서 content_type 을 지정해주는 클래스를 새로 만든다. 그리고 나서 만들어두었던 RecentPostsFeed 클래스 안에 'feed_type' 속성을 지정해주면 된다.

[ feeds.py ]
​​​​​​​from django.contrib.syndication.views import Feed
from django.urls import reverse
from blog.models import Post
from django.utils.feedgenerator import DefaultFeed


class CorrectMimeTypeFeed(DefaultFeed):
    content_type = 'application/xml; charset=utf-8'


class RecentPostsFeed(Feed):
    title = 'Recent posts from Windy Bay blog'
    link = '/feeds/'
    description = 'Updates on additions and changes to posts'
    feed_type = CorrectMimeTypeFeed

    def items(self):
        return Post.objects.filter(published_date__isnull=False).order_by('-published_date')[:10]

    def item_title(self, item):
        return item.title

    def item_description(self, item):
        return item.content

    def item_link(self, item):
        return reverse('blog:post_detail', args=[item.pk])

 

이렇게 하면 브라우저에서 feed의 내용을 읽어 잘 정리된 XML 포맷으로 보여주게 된다.

 

 

사실 RSS 피드를 이용해서 글을 구독해본 적이 없어서 관련된 내용을 잘 모르고 있었는데, 내용을 공부하면서 RSS 리더들을 이용해보니 잘 정리된 블로그들을 모아서 구독하는 데는 편리한 점이 있는것 같다. 피드를 작성해 두면 인터넷에 사이트를 노출시키는 데도 도움이 되니 가능하면 RSS 피드도 제공하는 것이 좋겠다.



최근 글 목록