Djangoのみでテーブル作成してみた


# Background
表示側に配列で複数の要素を受け取って、そこから `<table></table>` 使って表示させたい場合です。
5段列で表示させたいとなった場合はどこかで列分の割り算をする場面が出てきます。

javascriptであれば、

```javascript
    var i = 0;
    var cols = 5; //列数
    var row_ele = NaN;

    for (key in dataset){
        if (i == 0){
            row_ele = NaN;
            row_ele = $("<tr></tr>");
        } 

        var cell = $("<td></td>");
        cell.text(dataset[key]);
        row_ele.append(cell);

        if (i == cols - 1){
            i = 0;
            $("table").append(row_ele);
        } else {
            i++;
        }
    }
```
と書けそうです。

ですが、標準のDjangoではtemplate内では計算はできません。
ここでは、`django-mathfilters`モジュールを紹介しつつ、計算方法を書いてみます。

# dataset & list view
サンプル例として、twitterでトレンドに上がったワード約100件分を使っています。

```python:views.py
from django.views.generic import TemplateView

class IndexView(TemplateView):
    template_name = 'index.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        words = ['全面停止','#彼氏と彼女の身長差は13cmがベスト','仕事始め','板野友美','ともちん結婚'
                ,'外国人の新規入国','ビジネス関係者','#解決KingandPrince','#スッキリ','#あさイチ'
                ,'鬼滅声優','リモート生出演','学徒動員','#おちょやん','満員電車'
                ,'小池氏の失政','仕事初め','大学院生','教員の医療現場','看護系大学'
                ,'浪川さん','いちごの日','完全勝利S','高津監督','宣言発令要請'
                ,'浅沼さん','婚姻届証人欄','秋元康氏','千代ちゃん','中山1R'
                ,'刀剣男士めし','奎二くん','豊洲市場','仕事はじめ','ミノタウロスの皿'
                ,'寒の入り','高校サッカー緊急事態宣言','囲碁の日','イングランド','新人部門'
                ,'イチゴの日','不法就労・ギャラ無申告','まんばちゃん','静岡開催','旭川医大学長発言'
                ,'テレワーク','ウーマンラッシュアワー村本','すしざんまい','埼玉自粛','大間産本マグロ'
                ,'鬼滅声優','仕事初め','大学院生','教員の医療現場','いちごの日'
                ,'看護系大学','浪川さん','完全勝利S','宣言発令要請','高津監督'
                ,'婚姻届証人欄','秋元康氏','浅沼さん','千代ちゃん','奎二くん'
                ,'刀剣男士めし','豊洲市場','仕事はじめ','ミノタウロスの皿','イングランド'
                ,'囲碁の日','寒の入り','まんばちゃん','新人部門','イチゴの日'
                ,'高校サッカー緊急事態宣言','旭川医大学長発言','静岡開催','大間産本マグロ'
                ,'埼玉自粛','テレワーク','すしざんまい','板野さん','不法就労・ギャラ無申告'
                ,'はまっする','全面停止','仕事始め','#彼氏と彼女の身長差は13cmがベスト','板野友美'
                ,'ともちん結婚','外国人の新規入国','ビジネス関係者','#解決KingandPrince','#おちょやん'
                ,'#スッキリ','#あさイチ','リモート生出演','小池氏の失政','学徒動員'
                ,'満員電車']
        context["tweets"] = words 
        return context
```

```html:index.html
<!DOCTYPE HTML>

<html>
    <head> </head>
    <body> 
        <h1> mathfilter </h1>
            <ul>
            {% for item in tweets %}
                <li>{{item}}</li>
            {% endfor %}
            </ul>
    </body>
</html>
```

tweetsをキーとしてツイートワードが入っている配列を格納して、view側に送っていて、`{% for item in tweets %}{% endfor %}` でfor文を使って各要素を描画しています。

表示は一列のリスト表示になります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288206/ff6e0c53-8845-6355-0ef9-7ac0bc7dfe42.png" width=50%>


# add module

次に`django-mathfilters` を追加します。モジュールをpipでインストールをして、`settings.py`でアプリケーションを追加します。

```bash
pip3 install django-mathfilters
```

```settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'mathfilters'
]
```

# improvement

```html
<!DOCTYPE HTML>
{% load mathfilters %} <!-- html内で定義 -->

<html>
    <head> </head>
    <body> 
        <h1> mathfilter </h1>
            <table>
            {% for item in tweets %}
                {% with index=forloop.counter0 %} <!-- index を取得 -->
                    {% if index|mod:5 == 0 %} <tr> {% endif %}
                        <td>
                            {{item}}
                        </td>
                    {% if index|mod:5 == 4 %} </tr> {% endif %}
                {% endwith %}
            {% endfor %}
            </table>
    </body>
</html>
```
`{% with index=forloop.counter0 %}{% endwith %}` とすると `for i, item in enumerate(range(...)): print(i)`みたいにインデックスの取得ができます。この機能はDjangoの標準にあります。
`index|mod:5` が 今回紹介したい`mathfilters`の機能で数字の余りを算出してくれます。この他にも`addition` `sub` `mul` `div` をつけると四則演算ができます。
ここでは`index % 5 == 0`だったら先頭に`<tr>`をつけ、`index % 5 == 4`であれば最後尾に`</tr>`をつける実装をしています。

ブラウザは以下の通りにテーブルの5段列で表示されます。
![capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288206/76efc3e0-d93f-0f09-70f0-f63ee0aeaf3c.png)


# Reference
- [Djangoのtemplateで演算処理を行う方法](https://qiita.com/ba--shi/items/013455f22d758bb74ec4)
- [Django Template(テンプレート)で ループカウンタ番号を表示](https://opendata-web.site/blog/entry/17/)
- [[Django]テンプレート内で引き算（減算）する方法](https://codelab.website/django-template-sub/)