質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Bootstrap

BootstrapはウェブサイトデザインやUIのWebアプリケーションを素早く 作成する可能なCSSフレームワークです。 Twitter風のデザインを作成することができます。

Q&A

解決済

1回答

4865閲覧

テンプレート内のfor文で、前の要素と頭文字を比較する

winarrows

総合スコア13

Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Bootstrap

BootstrapはウェブサイトデザインやUIのWebアプリケーションを素早く 作成する可能なCSSフレームワークです。 Twitter風のデザインを作成することができます。

1グッド

1クリップ

投稿2019/03/30 13:48

前提・実現したいこと

Django(2.1.5),Bootstrap4で人物のデータベースのようなものを作っています。

人物が多いので、行ごと(あ行、か行・・・)または50音ごと(あ、い・・・)にグループ分けしてアコーディオンにしたいと考えています。

現状と課題

現在は、人物一覧を表示するテンプレート内でfor文によってモデルから一覧を作成しています。
→グループ分けされず単純にリストとして表示されている。

テンプレート内のfor文で、インデックスが一つ前のものと比較できれば、あるいは、変数を保持出来れば、頭文字を比較して異なっているときにグループを切り替える処理ができると思うのですが、手段がわかりません。
(よりスマートな手段があればそのほうが望ましいです。)

models.pyの中で頭文字を取得する関数は定義しました。

該当のソースコード

models.py

Python

1from django.db import models 2 3class Person(models.Model): 4 name = models.CharField('人物の名前',max_length=255,unique=True) 5 name_kana = models.CharField('ふりがな',max_length=255,default='ん') 6 7 def __str__(self): 8 return self.name 9 10 def kana_initial(self): 11 if self.name_kana is not None: 12 return self.name_kana[0] 13 else: 14 return "ん"

views.py

Python

1from django.shortcuts import render 2from .models import Person 3 4def index(request): 5 person_all = Person.objects.all().order_by('name_kana') 6 return render(request, 'App/index.html',{'person_all':person_all})

templates/App/index.html(抜粋)

HTML

1 <ul> 2 {% for person in person_all.all %} 3 <li>{{person.name}}</li> 4 {% endfor %} 5 </ul>
ak_suzuki👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

(「テンプレート内のfor文で、前の要素と頭文字を比較する方法」についての直接の回答ではありません)

Person というモデルの object をグループ分けして出力されたいとのことですね。

そのような処理は、テンプレートの中でやるよりは view の中でやられた方がよいかと思います。例えば、 view の中で

python

1from itertools import groupby 2 3person_all = Person.objects.all().order_by('name_kana') 4grouped_persons = {k: list(v) for k, v in groupby(person_all, lambda p: p.kana_initial())} 5# => {'あ': (「あ」から始まる人のリスト), 'い': (「い」から始まる人のリスト), ...}

という感じにすると、五十音別にグルーピングができるので、あとはこれをテンプレートに渡して出力するとスムーズに実現できるのではないかと思います。

html

1{% for group_key, persons in grouped_persons.items %} 2<h3>{{ group_key }}</h3> 3<ul> 4 {% for person in persons %} 5 <li>{{person.name}}</li> 6 {% endfor %} 7</ul> 8{% endfor %}

(動作確認はしていないので、コピペでの利用はせずアイデアのみ参考にしてください)

参考:

追記 2019/04/01

ご解決されたようでよかったです。

ご提案のまま実行すると「Need 2 values to unpack in for loop; got 1.」とエラーが出ましたが、...

ご指摘いただきありがとうございます。おっしゃるとおりですね。誰かが後で参考にするときのために上の回答を修正しておきます。

それと、 grouped_personsdict にしておくとテンプレート側で .items をつけないといけないのであれば、次のように、 groupby() の戻り値をそのまま grouped_persons に入れておいて

python

1grouped_persons = groupby(person_all, lambda p: p.kana_initial())

テンプレート側は次のように書く形でもよかったかもしれませんね。

html

1{% for group_key, persons in grouped_persons %} 2<h3>{{ group_key }}</h3> 3<ul> 4 {% for person in persons %} 5 <li>{{person.name}}</li> 6 {% endfor %} 7</ul> 8{% endfor %}

追記 2019/04/01 その 2

別件で調べものをしていてたまたま知ったのですが、 Django の組み込みのタグに regroup というものがあり、これがまさに今回の用途に使えるもののようです。私の当初の回答が覆ってしまいますが、よろしければチェックしてみてください。

公式ドキュメントを読むかぎりでは、次のような形で使えるようです。

view から次の変数がテンプレートに渡されたものとします。

python

1person_all = Person.objects.all().order_by('name_kana')

regroup タグを使うと、上のアプローチと同様の出力結果が次の記述で得られるようです。

text

1{% regroup person_all by kana_initial as grouped_persons %} 2 3<ul> 4{% for group in grouped_persons %} 5 <h3>{{ group.grouper }}</h3> 6 <ul> 7 {% for person in group.list %} 8 <li>{{ person.name }}</li> 9 {% endfor %} 10 </ul> 11{% endfor %}

kana_initial のところはメソッド kana_initial() をプロパティ化するなりしないと正しく動かないかもしれませんが、ともあれ、別解として regroup タグを使うアプローチもあったようです。私自身勉強になりました。ご参考まで……

投稿2019/03/31 08:24

編集2019/04/01 13:04
gh640

総合スコア1407

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

winarrows

2019/03/31 13:44 編集

ご回答ありがとうございました。 まさにこのようなスマートな方法を探していました。 ご提案のまま実行すると「Need 2 values to unpack in for loop; got 1.」とエラーが出ましたが、 {% for group_key, persons in grouped_persons.items %} としたら動作しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問