2018年7月12日木曜日
ウズマスター戦記
ウズマスター戦記 https://www.uzumax.org/2018/07/django-regroup.html

Djangoのテンプレートタグ 「regroup」 同じ属性値でグループ化

日本一平凡なDjangoバナー

Djangoのはテンプレートタグ「regroup」は、単純に一覧として入っているリストから属性値毎にグループ化して表示する機能です。

テンプレートタグの中でもかなり変わった機能ですので、当サイトを参考にして頂ければと思います。


概要

テンプレートタグ「regroup」は、SQLで言うところのGroupByのようなものです。

以下のように世界の国、都市、人口が入ったオブジェクトのリストがコンテキストにセットされてくるとしますよね。

context = {}
cities = [
    {'name': 'ムンバイ', 'population': '19,000,000', 'country': 'インド'},
    {'name': 'カルカッタ', 'population': '15,000,000', 'country': 'インド'},
    {'name': 'ニューヨーク', 'population': '20,000,000', 'country': 'アメリカ'},
    {'name': 'シカゴ', 'population': '7,000,000', 'country': 'アメリカ'},
    {'name': '東京', 'population': '33,000,000', 'country': '日本'},
]
context["cities"] = cities

イメージ的には、これを以下のように組み替えるようなものです。

cities = [
    {'country': 'インド', 'cities': [
        {'name': 'ムンバイ', 'population': '19,000,000'},
        {'name': 'カルカッタ', 'population': '15,000,000'}
    ]},
    {'country': 'アメリカ', 'cities': [
        {'name': 'ニューヨーク', 'population': '20,000,000'},
        {'name': 'シカゴ', 'population': '7,000,000'},
    ]},
    {'country': '日本', 'cities': [
        {'name': '東京', 'population': '33,000,000'},
    ]},
]
context["cities"] = cities

属性を指定し、属性毎(この例だと、国)にグルーピングしてリストを作り直す。
これがregroupの機能です。

では、実装を見ていきましょう。

views.py

上記の例と同じく、これを流し込みます。

context = {}
cities = [
    {'name': 'ムンバイ', 'population': '19,000,000', 'country': 'インド'},
    {'name': 'カルカッタ', 'population': '15,000,000', 'country': 'インド'},
    {'name': 'ニューヨーク', 'population': '20,000,000', 'country': 'アメリカ'},
    {'name': 'シカゴ', 'population': '7,000,000', 'country': 'アメリカ'},
    {'name': '東京', 'population': '33,000,000', 'country': '日本'},
]
context["cities"] = cities

テンプレート

テンプレート側ではこのように書きます。

{% regroup cities by country as country_list %}
<table class="table table-striped table-bordered">
    {% for country in country_list %}
    <thead>
    <tr>
        <td colspan="2" class="bg-primary">{{ country.grouper }}</td>
    </tr>
    <tr class="bg-info">
        <td>都市</td>
        <td>人口</td>
    </tr>
    </thead>
    <tbody>
    {% for city in country.list %}
    <tr>
        <td>{{ city.name }}</td>
        <td>{{ city.population }}</td>
    </tr>
    {% endfor %}
    </tbody>
    {% endfor %}
</table>

「{% regroup cities by country as country_list %}」が本稿のキモとなるグループ化の宣言ですね。

元々は「cities」という名前でコンテキストに入っていたリストを「country」でグループ化したものを「country_list」という名前で作っているわけです。

結果

こんな風に出力されました。


なかなか面白い機能ですね。

注意事項

なお、regroupタグはソート機能は有していません。

このタグを使う場合、前もってviews.py側でグループ化する属性でソートしておく必要があります。

と考えると、やっぱりこれ、わざわざネイティブSQLでGroupByを書かなくて済むようにする為に面倒臭がりのプラグらまーが編み出した裏技機能だと思いますよ。

ORマッピングではGroupByを実現するのは難しいですが、OrderByは簡単に出来ますからね。

出展

公式サイトはこちら。


バックナンバー


0 件のコメント:

コメントを投稿

お気軽にコメント下さい。