0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

django復習(tables2)

Posted at

とりあえずdjangoの復習用に適当にテーブルを作成。
投入データは下記から取得。
日本政府が出してるっぽいデータ

from django.db import models
from datetime import datetime


# 人口テーブル
class Population(models.Model):
    prefectures_code = models.CharField(max_length=10,verbose_name="都道府県コード", null=False) 
    prefectures = models.CharField(max_length=10,verbose_name="都道府県", null=False) 
    era =  models.CharField(max_length=500, verbose_name="元号", null=False)
    jp_calendar =  models.CharField(max_length=500, verbose_name="和暦", null=False)
    year =  models.CharField(max_length=500, verbose_name="西暦", null=False)
    population =  models.CharField(max_length=500, verbose_name="人口", null=False)
    man =  models.CharField(max_length=500, verbose_name="男", null=False)
    woman =  models.CharField(max_length=500, verbose_name="女", null=False)
    create_date = models.DateTimeField(default=datetime.now, null=True, verbose_name="登録日")

    def __str__(self):
        return self.prefectures

適当すぎて人口の数値部分も文字列で作成。
問題ないかと思いそのまま続行した結果、色々被害続出。

・tables2の復習で最新年度の人口の表を作成したが、
 ソート機能が文字列(辞書順)でソートしてしまうため、正しくソートできない。
 例:
  123000,200,500があった場合、辞書順なので1文字目を取って
  123000 < 200 < 500 になる。

・matplotlibの復習で特定の県について年ごとの人口の推移を見ようとしたが、
 人口が文字列のため、グラフがちゃんとできない。
 例:
  1年間で100万人→120万人に増えても1メモリ分しか増加しない。
  1年間で100万人→200万人に増えても1メモリ分しか増加しない。

matplotlibの方は特にハマらなかったのでtables2についてメモ。
(model直してDB作り直すのが一番ですが、勉強も兼ねてmodelはそのままで続行)

table.pyのソース

from population.models import Population
import django_tables2 as tables
from django_tables2.utils import A
from population.models import Population

class ButtonLinkColumn(tables.LinkColumn):
    """
    リンク表示用カラム(ボタン)
    """
    def render(self, record, value):
        if record.count > 0:
            # ステータス:完了
            return "データ表示"
        else:
            # ステータス:完了以外
            return ""
            
class PopulationTable(tables.Table):
    """
    人口画面用テーブル
    Population
    """
    prefectures = tables.Column(verbose_name="都道府県")
    # リンク用
    plot = tables.LinkColumn("population:pop_plot", args=[A("prefectures_code")], 
                    verbose_name = "",text="人口グラフ", 
                    attrs={"a": {"class": "btn btn-success text-nowrap"}} 
                    )
    population = tables.Column(verbose_name="総人口")
    man = tables.Column(verbose_name="人口(男性)")
    woman = tables.Column(verbose_name="人口(女性)")

    class Meta:
        model = Population
        template_name = 'django_tables2/bootstrap4.html'
        # 表示する列column
        fields = ('prefectures_code',
                'prefectures',
                'plot',
                'population',
                'man',
                'woman',

        )    
        attrs = {"class": "table table-striped"}

django-tables2の参考サイト
参考サイトを見るとorder_カラム名で対象のカラムのソート条件をいじれるらしい。

from django.db.models.functions import Length

~以下中略~

    def order_name(self, queryset, is_descending):
        queryset = queryset.annotate(
            length=Length("first_name")
        ).order_by(("-" if is_descending else "") + "length")
        return (queryset, True)

真似してmanでやってみると、桁数でのソートはできた。

    def order_man(self, queryset, is_descending):
        queryset = queryset.annotate(
            length=Length("man")
        ).order_by(("-" if is_descending else "") + "length")
        return (queryset, True)

じゃぁ次は数値でソートしたいと思ったが、ここからが問題。
理解度が低いせいかLength部分に何が入るか分からず、そこを調べるのに時間がかかった。

色々調べたが、googleでは上手く見つけられずdjango.db.models.functionsを調べることで解決した。

from .comparison import Cast, Coalesce, Greatest, Least, NullIf
from .datetime import (
    Extract, ExtractDay, ExtractHour, ExtractIsoWeekDay, ExtractIsoYear,
    ExtractMinute, ExtractMonth, ExtractQuarter, ExtractSecond, ExtractWeek,
    ExtractWeekDay, ExtractYear, Now, Trunc, TruncDate, TruncDay, TruncHour,
    TruncMinute, TruncMonth, TruncQuarter, TruncSecond, TruncTime, TruncWeek,
    TruncYear,
)
from .math import (
    Abs, ACos, ASin, ATan, ATan2, Ceil, Cos, Cot, Degrees, Exp, Floor, Ln, Log,
    Mod, Pi, Power, Radians, Round, Sign, Sin, Sqrt, Tan,
)
from .text import (
    MD5, SHA1, SHA224, SHA256, SHA384, SHA512, Chr, Concat, ConcatPair, Left,
    Length, Lower, LPad, LTrim, Ord, Repeat, Replace, Reverse, Right, RPad,
    RTrim, StrIndex, Substr, Trim, Upper,
)
from .window import (
    CumeDist, DenseRank, FirstValue, Lag, LastValue, Lead, NthValue, Ntile,
    PercentRank, Rank, RowNumber,
)

__all__ = [
    # comparison and conversion
    'Cast', 'Coalesce', 'Greatest', 'Least', 'NullIf',
    # datetime
    'Extract', 'ExtractDay', 'ExtractHour', 'ExtractMinute', 'ExtractMonth',
    'ExtractQuarter', 'ExtractSecond', 'ExtractWeek', 'ExtractIsoWeekDay',
    'ExtractWeekDay', 'ExtractIsoYear', 'ExtractYear', 'Now', 'Trunc',
    'TruncDate', 'TruncDay', 'TruncHour', 'TruncMinute', 'TruncMonth',
    'TruncQuarter', 'TruncSecond', 'TruncTime', 'TruncWeek', 'TruncYear',
    # math
    'Abs', 'ACos', 'ASin', 'ATan', 'ATan2', 'Ceil', 'Cos', 'Cot', 'Degrees',
    'Exp', 'Floor', 'Ln', 'Log', 'Mod', 'Pi', 'Power', 'Radians', 'Round',
    'Sign', 'Sin', 'Sqrt', 'Tan',
    # text
    'MD5', 'SHA1', 'SHA224', 'SHA256', 'SHA384', 'SHA512', 'Chr', 'Concat',
    'ConcatPair', 'Left', 'Length', 'Lower', 'LPad', 'LTrim', 'Ord', 'Repeat',
    'Replace', 'Reverse', 'Right', 'RPad', 'RTrim', 'StrIndex', 'Substr',
    'Trim', 'Upper',
    # window
    'CumeDist', 'DenseRank', 'FirstValue', 'Lag', 'LastValue', 'Lead',
    'NthValue', 'Ntile', 'PercentRank', 'Rank', 'RowNumber',
]

上記にあるメソッドは大体使えるっぽいのでAbs(絶対値)を使って解決した。

    def order_population(self, queryset, is_descending):
        queryset = queryset.annotate(
            abs=Abs("population")
        ).order_by(("-" if is_descending else "") + "abs")
        return (queryset, True)

    def order_man(self, queryset, is_descending):
        queryset = queryset.annotate(
            abs=Abs("man")
        ).order_by(("-" if is_descending else "") + "abs")
        return (queryset, True)

    def order_woman(self, queryset, is_descending):
        queryset = queryset.annotate(
            abs=Abs("woman")
        ).order_by(("-" if is_descending else "") + "abs")
        return (queryset, True)
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?