Djangoで、配信フィードを生成する

Twitterでシェア FaceBookでシェア はてなブックマークでシェア

Python - Django
2018年11月22日21:29に更新(約21日前)
2018年11月5日23:58に作成(約38日前)

旧ブログ移行記事です。

概要

今でもRSS等はよく使われていますが、Djangoではこれも自動で生成できます。 サイトマップに似ていますが、それよりも全体的に単純です。

初期設定

以下のようなモデルを例に作ります。

class Post(models.Model):
    title = models.CharField('タイトル', max_length=255)
    text = models.TextField('本文')
    created_at = models.DateTimeField('作成日', default=timezone.now)

    def __str__(self):
        return self.title

アプリケーションのurls.py サイトマップのときと同様に、reverseresolve_urlといった逆引きでこのurls.pyが参照されるので、定義しておく必要があります。

from django.urls import path
from . import views

app_name = 'app'

urlpatterns = [
    path('', views.PostIndex.as_view(), name='list'),
    path('detail/<int:pk>/', views.PostDetail.as_view(), name='detail'),
]

使い方

プロジェクトのurls.pyを編集します。

from django.contrib import admin
from django.contrib.syndication.views import Feed
from django.shortcuts import resolve_url
from django.urls import path, include, reverse_lazy
from app.models import Post


class LatestPostFeed(Feed):
    title = "naritoブログ 最新記事"
    link = reverse_lazy('app:list')
    description = "naritoブログから、記事の最新情報をお届けします。"

    def items(self):
        return Post.objects.order_by('-created_at')[:5]

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

    def item_description(self, item):
        return item.text[:10]  # 本文の20文字目までをとりあえず説明に。

    def item_link(self, item):
        return resolve_url('app:detail', pk=item.pk)


urlpatterns = [
    path('admin/', admin.site.urls),
    path('latest/feed/', LatestPostFeed()),
    path('', include('app.urls')),
]

サイトマップのときと同様に、urls.pyが見にくいなーと思ったらfeeds.pyなどに分割しましょう。 今回であれば、LatestPostFeedクラスだけ移し、それをimportすればOKです。

流れとしてはまず、urlpatternsリストにfeed用の定義をします。

path('latest/feed/', LatestPostFeed()),

そしてFeedクラスを作ります。

class LatestPostFeed(Feed):
    title = "naritoブログ 最新記事"
    link = reverse_lazy('app:list')
    description = "naritoブログから、記事の最新情報をお届けします。"

    def items(self):
        return Post.objects.order_by('-created_at')[:5]

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

    def item_description(self, item):
        return item.text[:10]  # 本文の20文字目までをとりあえず説明に。

    def item_link(self, item):
        return resolve_url('app:detail', pk=item.pk)

デフォルトではRSS 2.0が利用されますが、クラス属性でそれを変更できます。

from django.utils.feedgenerator import Atom1Feed
...
...
class AtomLatestPostFeed(Feed):
    feed_type = Atom1Feed
    ...
    ...

実際に生成されるFeed(xml)を見せておきましょう。 以下のようなFeedが作成されます。

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>naritoブログ 最新記事</title>
        <link>http://127.0.0.1:8000/</link>
        <description>naritoブログから、記事の最新情報をお届けします。</description>
        <atom:link href="http://127.0.0.1:8000/latest/feed/" rel="self"></atom:link>
        <language>ja</language>
        <lastBuildDate>Tue, 18 Sep 2018 15:14:51 +0000</lastBuildDate>
        <item>
            <title>新しい書籍を出します。</title>
            <link>http://127.0.0.1:8000/detail/3/</link>
            <description>11月が12月頃に.....</description>
            <guid>http://127.0.0.1:8000/detail/3/</guid>
        </item>
        <item>
            <title>回転ずしに行きました。</title>
            <link>http://127.0.0.1:8000/detail/2/</link>
            <description>花丸という寿司屋です。おいし...</description>
            <guid>http://127.0.0.1:8000/detail/2/</guid>
        </item>
        <item>
            <title>ココイチにいきました。</title>
            <link>http://127.0.0.1:8000/detail/1/</link>
            <description>安定しておいしいです....</description>
            <guid>http://127.0.0.1:8000/detail/1/</guid>
        </item>
    </channel>
</rss>

<channels>内のtitle, link, descriptionはそのままクラス属性の内容です。 <item>title, link, descriptionは、今回メソッドで定義している部分ですね。 サイトマップと同様に、各属性はメソッドでもクラス属性でも定義できたりします。

RSSとAtom両方配信する

RSSとAtomの両方を配信するということも簡単です。

class LatestPostFeed(Feed):
...
...
...
class AtomLatestPostFeed(LatestPostFeed):
    feed_type = Atom1Feed
    subtitle = LatestPostFeed.description


urlpatterns = [
    path('admin/', admin.site.urls),
    path('latest/feed/', LatestPostFeed()),
    path('atom/latest/feed/', AtomLatestPostFeed()),  # Atom
    path('', include('app.urls')),
]

LatestPostFeedを継承しつつ、feed_typeをAtomにしました。Atomはdescriptionのかわりにsubtitleという属性になるので、それも設定します。

class AtomLatestPostFeed(LatestPostFeed):
    feed_type = Atom1Feed
    subtitle = LatestPostFeed.description

各要素がどんな意味を持つかは、分かりやすいページがあるので、そちらを確認してください。 どんな属性・メソッドを定義できるかは、Djangoのドキュメントがわかりやすいです。

Twitterでシェア FaceBookでシェア はてなブックマークでシェア

記事にコメントする