備忘録です。
今回はnavbarに設置した検索ボックスを使ってアプリケーション内を横断検索するコードの実装についての備忘録。
Bootstrapのnavbarに設置されている検索窓を使った横断検索
前提としてアプリケーション内に下記の4つのページとそれに対応したテーブルがあるとして実装します。
- Projectsページ:プロジェクトを一覧で表示
- Knowledgeページ:メモ的な備忘録用を一覧で表示
- Aspirationsページ:やりたいことを一覧で表示
- Schedulerページ:スケジュールを一覧で表示
その1 navbarの検索窓のコードを修正
bootstrapから検索窓付きのnavbarを使用している場合、フォームに関するコードがあると思います。そちらを下記のように修正します。
# navbar.html
<form method="POST" action="{{ url_for('search')}}" class="d-flex">
{{ form.hidden_tag() }}
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search" name="searched">
<button class="btn btn-outline-secondary" type="submit">Search</button>
</form>
formタグ内にPOSTのmethodと遷移先のurlを追記
inputタグ内に識別用のnameをsearchedという形で追記
# app.py
class SearchForm(FlaskForm):
searched = StringField('Searched', validators=[DataRequired()])
submit = SubmitField('Submit')
検索用のフォームクラスを作成します。
その3 navbarからフォームを渡すため下記のコードを追記
# app.py
@app.context_processor
def base():
form = SearchForm()
return dict(form=form)
その4 検索窓にキーフレーズを入れた時の動きをまとめる
# app.py
@app.route('/search', methods=['POST'])
def search():
form = SearchForm()
if form.validate_on_submit():
keyphrase = form.searched.data
projects = Project.query.filter(Project.p_content.like('%' + keyphrase + '%'))
projects = projects.order_by(Project.p_crated_at).all()
knowledges = Knowledge.query.filter(Knowledge.k_content.like('%' + keyphrase + '%'))
knowledges = knowledges.order_by(Knowledge.k_created_at).all()
aspirations = Aspiration.query.filter(Aspiration.content.like('%' + keyphrase + '%'))
aspirations = aspirations.order_by(Aspiration.created_at).all()
schedulers = Scheduler.query.filter(Scheduler.s_title.like('%' + keyphrase + '%'))
schedulers = schedulers.order_by(Scheduler.s_created_at).all()
return render_template("search.html", form=form, searched=keyphrase, projects=projects, knowledges=knowledges, aspirations=aspirations, schedulers=schedulers)
その5 検索をまとめて表示する
最終的にこんな感じで横断検索し表示する。(下記表示ページのコードあり)
app.pyから渡されてきたリストはjinjaで適時表示するように実装する。
# search.html
{% extends "base.html" %}
{% block content %}
<br/>
<h2>You Searched For this Key Phrase...{{ searched }}</h2>
<br/>
<h3 class="mt-4 mb-3 border-bottom border-secondary border-3">Projects</h3>
{% if projects != [] %}
{% for project in projects %}
<div class="{% if project.p_status == 0 %}shadow p-3 mb-5 bg-body rounded{% else %}shadow p-3 mb-5 bg-secondary rounded text-white{% endif %}">
<h2><a href="{{ url_for('project', id=project.id)}}" style="text-decoration: none; color: darkblue;">{{ project.p_title }}</a></h2>
<small>作成日:{{ project.p_crated_at.strftime('%Y-%m-%d %H:%M') }}</small><br/>
{% if project.p_completed_at %}
<small>完了日:{{ project.p_completed_at.strftime('%Y-%m-%d')}}</small><br/>
{% endif %}
{{ project.p_content|safe }} <br/><br/>
<a href="{{ url_for('edit_project', id=project.id )}}" class="btn btn-outline-secondary btn-sm">編集</a>
<a href="{{ url_for('delete_project', id=project.id)}}" class="btn btn-outline-danger btn-sm">削除</a>
<!-- ボタンをクリックした際にprojectのidを同時に渡し、add_element/p_idというurlを作る -->
<a href="{{ url_for('add_element', p_id=project.id)}}" class='btn btn-outline-success btn-sm' >要件追加</a>
</div>
{% endfor %}
{% else %}
<p>{{ searched }}に一致する項目はありませんでした...</p><br/>
{% endif %}
<br/>
<h3 class="mt-4 mb-3 border-bottom border-secondary border-3">Knowledges</h3>
{% if knowledges != [] %}
{% 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|safe }} <br/><br/>
{{ knowledge.k_tag}} <br/><br/>
{% if current_user.is_authenticated %}
<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>
{% endif %}
</div>
{% endfor %}
{% else %}
<p>{{ searched }}に一致する項目はありませんでした...</p><br/>
{% endif %}
<br/>
<h3 class="mt-4 mb-3 border-bottom border-secondary border-3">Aspirations</h3>
{% if aspirations != [] %}
{% for aspiration in aspirations %}
<div class="{% if aspiration.status == 0 %}shadow p-3 mb-5 bg-body rounded{% else %}shadow p-3 mb-5 bg-secondary rounded text-white{% endif %}">
<h2>{{ aspiration.title }}</h2>
<small>作成日:{{ aspiration.created_at.strftime('%Y-%m-%d %H:%M') }}</small><br/>
{% if aspiration.completed_at %}
<small>完了日:{{ aspiration.completed_at.strftime('%Y-%m-%d')}}</small><br/>
{% endif %}
{{ aspiration.content }} <br/><br/>
<a href="{{ url_for('edit_aspiration', id=aspiration.id )}}" class="btn btn-outline-secondary btn-sm">編集</a>
<a href="{{ url_for('deleat_aspiration', id=aspiration.id)}}" class="btn btn-outline-danger btn-sm">削除</a>
</div>
{% endfor %}
{% else %}
<p>{{ searched }}に一致する項目はありませんでした...</p><br/>
{% endif %}
<br/>
<h3 class="mt-4 mb-3 border-bottom border-secondary border-3">Schedule</h3>
{% if aspirations != [] %}
{% for schedule in schedulers %}
<div class="{% if schedule.s_status == 0 %}shadow p-3 mb-3 bg-body rounded{% else %}shadow p-3 mb-5 bg-secondary rounded text-white{% endif %}">
<a href="{{ url_for('delete_schedule', id=schedule.id)}}" class="btn btn-outline-danger btn-sm float-end ms-2">削除</a>
<a href="{{ url_for('edit_schedule', id=schedule.id)}}" class="btn btn-outline-secondary btn-sm float-end">編集</a>
<p class="float-"><small>日程: {{ schedule.s_date.strftime('%Y-%m-%d') }}</small> <span class="fs-4">{{ schedule.s_title }}</span></p>
</div>
{% endfor %}
{% else %}
<p>{{ searched }}に一致する項目はありませんでした...</p><br/>
{% endif %}
<br/><br/>
{% endblock %}