ちゃぱブログ / エンジニアリング / マネジメント

とあるプロダクトの運用組織のマネジメントしてる人の雑記。主にエンジニアリングやマネジメントのことを書きます。ときおりプチ情報も

Data Tablesの表中にリンクを埋め込む

はじめに

django-datatables-viewを使ってAjaxで便利な一覧を作ることには成功したものの、そのままだと使いにくい。なぜなら一覧から詳細画面に遷移する、などのリンクがなかったから。これはどうしても必須だったので、調べて実装した。以下の記事の続きの位置づけ。

as-chapa.hatenablog.com

結論

「render_column」をオーバーライドして、指定の項目のときだけreturnを変えるようにする。 ソースはこちら。

github.com

実装としては以下の通り。

class BookJsonView(BaseDatatableView):
    model = Book
    columns = ['id', 'title', 'author']

    def render_column(self, row, column):
        if column == 'id':
            return f'<a href="/sample/bookdetail/{row.id}">{row.id}</a>'
        else:
            return super(BookJsonView, self).render_column(row, column)

「id」のときだけ、リンクとなるようにHTMLのタグをreturnした。

get_absolute_url()の定義でもうまくいくと思いきや・・・

django-datatables-viewのソースを見たところ、Modelにget_absolute_url()メソッドが書いてあると aタグとして返すように書いてある。

def render_column(self, row, column):
    """ Renders a column on a row. column can be given in a module notation eg. document.invoice.type
    """
    value = self._render_column(row, column)
    if value and hasattr(row, 'get_absolute_url'):
        return format_html('<a href="{}">{}</a>', row.get_absolute_url(), value)
    return value

Bitbucket

ほうほう、なるほど、きっとこっちの実装のほうがif文で拾う必要もなくキレイになるなぁと思い試した。

models.py

from django.db import models
from django.urls import reverse


class Book(models.Model):
    """本"""
    class Meta:
        db_table = 'book'
    
    title = models.CharField(verbose_name="本のタイトル", max_length=255)
    author = models.CharField(verbose_name="著者", max_length=255)

    def get_absolute_url(self):
        return reverse('sample:bookdetail', kwargs={'pk': self.pk})

こうすると、 views.py でわざわざ if column == 'id': なんてダサいif文をかまさなくて良くなる!と思ったが、最終形がイメージと違った・・・別に全部にリンクはいらないんだよな。というわけで、自分は「結論」に書いた実装とした。

f:id:as_chapa:20200905080204p:plain

参考までに全ソースはタグとして保存しておいた。

Release tag_get_absolute_url_sample · as-chapa/datatables · GitHub