ビジネスパーソン・ガジェット置場 empty lot for business

営業や仕事、それに伴う生活を便利に楽にするツール、ガジェットを作ります。既にあるツールも自分用にカスタマイズ。

python: Flaskアプリの作成12 タグでコンテンツをソートする

備忘録です。

今回の備忘録は記事を投稿するときに同時にタグを設定できるようにし、そのタグで記事をソートして表示する方法です。

タグ

同じタグがついている記事を集めて表示する

hatenaブログでもありますが、記事を投稿するときにタグをつけておけば、後でタグで記事を選別できます。同じ機能をFlaskのアプリに設置します。(今回、設置できるタグは1記事につき1つです)

 

その1 記事のテーブルにタグを設置

class Knowledge(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    k_title = db.Column(db.String(255))
    k_content = db.Column(db.Text)
        # タグ用のカラム
    k_tag = db.Column(db.String(100))
    k_created_at = db.Column(db.DateTime, default=datetime.now(pytz.timezone('Asia/Tokyo')))そ

そのまま、String型でカラムを作ります。

 

その2 記事一覧ページの上部にタグを表示する

タイトルの下にある2つのボタン(Flask、記事)が記事投稿時にタグとして登録したものを表示したものです。ボタンになっているので、こちらをクリックするとそのタグのページに飛ぶようにします。

 

一覧ページ用のコードは下記のようにしました。

#app.py

# ナレッジを一覧で表示するページ
@app.route('/knowledges')
def knowledges():
    knowledges = Knowledge.query.order_by(desc(Knowledge.k_created_at))
    tags = list(set([knowledge.k_tag for knowledge in knowledges]))
    return render_template('knowledges.html', knowledges=knowledges, tags=tags)

returnする前にtagsという変数にタグ(k_tag)としてDBに登録されているデータを集めて格納しています。

 

この時、タグの重複を削除するために一度、タグのリストをset()して再度list()しています。

 

htmlは下記のようにしました。

# knowledges.html

{% extends "base.html"%}

{% block content %}
<a href="{{url_for('add_knowledge')}}" class="btn btn-outline-primary float-end mt-2">ナレッジ登録</a>
<h1 class="mt-4">ナレッジ一覧</h1><br/>

# app.pyの関数で渡されたリストtagsをここで拾っています。forで取り出しボタンにして表示します。 {% for tag in tags %}
    # url_forでtag=tagでクリックしたtagを渡します <a href="{{ url_for('search_tag', tag=tag)}}" class="btn btn-outline-secondary btn-sm mb-2">{{ tag }}</a> {% endfor %}
{% for knowledge in knowledges %} <div class="shadow p-3 mb-5 bg-body rounded"> <h2>{{ knowledge.k_title }}</h2> <small>作成日:{{ knowledge.k_created_at.strftime('%Y-%m-%d %H:%M') }}</small><br/> {{ knowledge.k_content }} <br/><br/> {{ knowledge.k_tag}} <br/><br/> <a href="{{ url_for('edit_knowledge', id=knowledge.id) }}" class="btn btn-outline-secondary btn-sm">編集</a> <a href="{{ url_for('delete_knowledge', id=knowledge.id) }}" class="btn btn-outline-danger btn-sm">削除</a> </div> {% endfor %} {% endblock %}

 

その3 ボタンを押してタグのページに遷移させる

選択したタグのページを作ります。

# タグで検索したページ
@app.route('/knowledges/tags/<tag>')
def search_tag(tag):
    knowledges = Knowledge.query.filter(Knowledge.k_tag == tag).order_by(desc(Knowledge.k_created_at))
    return render_template('tags.html', knowledges=knowledges, tag=tag)

routeにtagを渡しています。これは一覧ページのボタンから渡されているタグです。

 

関数内でそのtagをもとにDBにfilterをかけて取り出し、念の為order_by()のdesc()で降順に並べ替え変数に格納しています。

 

returnでtagをさらに渡しているのは、表示するページでそのtagを使いたいからです。

 

{% extends "base.html"%}

{% block content %}
<a href="{{url_for('add_knowledge')}}" class="btn btn-outline-primary float-end mt-2">ナレッジ登録</a>

# app.pyで引数で渡すように設定したtagを使ってタイトルを表示しています
<h1 class="mt-4">{{tag}}</h1><br/>

# 渡されたリストを繰り返しで取り出して表示しています
{% for knowledge in knowledges %}
  <div class="shadow p-3 mb-5 bg-body rounded">
    <h2>{{ knowledge.k_title }}</h2>
    <small>作成日:{{ knowledge.k_created_at.strftime('%Y-%m-%d %H:%M') }}</small><br/>
    {{ knowledge.k_content }} <br/><br/>
    {{ knowledge.k_tag}}  <br/><br/>
    <a href="{{ url_for('edit_knowledge', id=knowledge.id) }}" class="btn btn-outline-secondary btn-sm">編集</a>
    <a href="{{ url_for('delete_knowledge', id=knowledge.id) }}" class="btn btn-outline-danger btn-sm">削除</a>

  </div>

{% endfor %}
{% endblock %}

 

今回は、ページ遷移させました。同じページで表示内容を変えることも考えたのですが、こっちの方が単純そうなのでこっちにしました。

 

「記事」というタグに紐づく記事を表示したページはこうなります。