[Django] タグクラウド機能を実装してみた
2017/05/24 09:00
  • Django でブログ機能を自前で制作したあと、内部リンク増加/検索性の向上を求めてタグ・クラウド
    を実装したときのまとめです。

    タグ・クラウドを実装した経緯

    色々あるのですが、

    1.関連する記事が自身で探しづらかったこと

    2.内部リンクが少なかったこと


    この2つが大きな理由でした。
    上記2つをもう少し説明します。

    1.「関連する記事が自身で探しづらかったこと」について

    当サイトでは記事をカテゴリごとに見る機能が実装されているのですが、
    間違ってカテゴリ指定することもあるし、適当な設計をしたため、
    記事 : カテゴリ = 1 : 1 の関係になっています。
    なので、1つの記事に対して複数のカテゴリを指定できない問題がありました。

    つけたタグごとに記事が表示される仕組みが導入できれば、多少は探してた記事にたどり着きやすくなるかな、と考えました。

    2.「内部リンクが少なかったこと」について

    まあ SEO 的な、しょうもない話です。(´・ω・`)

    models.py

    後述しますが、もともと tag カラムを持っていたので楽ができました。

    class Article(models.Model):
        subject = models.CharField(max_length=255)
        description = models.CharField(max_length=255, blank=True)
        content = models.TextField(blank=False)
        category = models.ForeignKey('ArticleCategory')
        tag = models.CharField(max_length=255, null=True, db_index=True, blank=True)
        is_publish = models.BooleanField(default=False)
        created_at = models.DateTimeField(auto_now_add=False)
        updated_at = models.DateTimeField(auto_now=False)
    

    ※コードはサンプルなので実際はもう少しカスタマイズしてます。

    urls.py

    以下のようなルーティングを追加しました。

    urlpatterns = [
        # 追記
        url(r'^article/tag/(?P<tag>.*)$', views.ArticleTagView.as_view(), name='articleTagIndex'),
    ]
    

    views.py

    views.py はこんな感じです。
    tag field にはカンマ区切りでキーワードが入力されている想定です。
    tag = "Django, Python, タグ機能"
    

    from django.views.generic import ListView
    
    
    class ArticleTagView(ListView):
        model = Article
        context_object_name = 'article_list'
        template_name = 'article/tag.jade'
        slug_field = 'tag'
        slug_url_kwarg = 'tag'
        paginate_by = 5
    
        def get_queryset(self):
            now = datetime.now()
            # 公開フラグON, 作成日が現在時刻より前の記事, かつ `tag` field に 検索タグ値 ( string ) が含まれているものだけフィルタする
            return Article.objects.filter(is_publish=1, created_at__lte=now, tag__icontains=self.kwargs.get('tag')).order_by('-updated_at')
    
        def get_context_data(self, **kwargs):
            context = super(ArticleTagView, self).get_context_data(**kwargs)
            object_name = super(ArticleTagView, self).get_context_object_name(self)
    
            article_tag = []
            for index, value in enumerate(context[object_name]):
                if value.tag:
                    # カンマをデリミタとして配列に詰める
                    tags = value.tag.split(',')
                    ''' 空白除去/空文字列排除 '''
                    for i, val in enumerate(tags):
                        tags[i] = val.strip()
                        # タグが重複していない場合だけ `article_tag` に詰める
                        if not tags[i] in article_tag:
                            article_tag.append(tags[i])
                    context[object_name][index].tag_list = tags
    
            return context
    

    templates/article/tag.jade

    テンプレートは以下。(最低限)
    例によって jade 記法で申し訳ない気持ち。笑
    for article in article_list
        ul.list-group
            li.list-group-item
                for tag in article.tag_list
                    a.btn.btn-success.btn-xs.mr-4(href='/article/tag/#{tag}') #{tag}
    

    以上です。

    人気ブログランキングへ ブログランキング・にほんブログ村へ
    ↑応援よろしくお願いします!m(_ _)m

  • <2017/05/24 09:00>
  • Python
  • DjangoPythontagタグタグクラウドJade
  • 新しい記事へ
    サイトを SSL 化したときに行ったこと

    古い記事へ
    [所感]膝をやらかしてこっ恥ずかしい体験!

profile picture

自己紹介的な何か

@wkmettyでついったーやってます。時々。 6年間勤めたゲーム会社を2018年2月に退職しフリーランスのプログラマに。 WordPress Core, WP-CLI コントリビューター。 お仕事募集中です。