te-touのブログ

音楽制作・車・プログラミング・旅行・その他考えてる事など、備忘録的なことも含めて個人的なページです。

Django weasyprintでPDF出力。(インストールと各種エラー対応と最終的に文字化け)




掲題の通り、Djangoで作成した画面をweasyprintを使ってPDF出力して印刷できるようにします。


まずは、weasyprintをインストールします。
しかし、いろんな物に依存関係があるようなので色々パッケージのインストールが必要です。
エラーを確認しながら進めます。なんか行き当たりばったりです。

環境
  • python : 3系
  • Django : version 3.0.2
  • SQLite
  • macOS Catalina

とりあえず、何かしらのアプリが作成されていることが前提です。
ついでにHomebrewもインストールされていることも前提です。

weasyprintインストール

Djangoのバーチャル環境にインストールするので、アプリをアクティベートしてからターミナルで以下のコマンドを打ちます。

pip install WeasyPrint

pipを最新化しろとメッセージが出たので、アップグレードします。

python3 -m pip install --upgrade pip
ソース

ざっくりソースを書きます。
views.py

from .models import Person
from django.http import HttpResponse
from django.template.loader import render_to_string
from weasyprint import HTML
import tempfile

def generate_pdf(request):
    from django.template.loader import get_template
# テンプレートを指定
    html_template = get_template('testapp/scoringsheet_list.html') 

    html_str = html_template.render({
#引数とかある場合は、ここに設定する。
      'Member': Member,
      'Scoringsheet': Scoringsheet,
                },request)  

    pdf_file = HTML('http://127.0.0.1:8000/scoringsheet?event=4').write_pdf(
# weasyprintではCSSを指定してあげないと参照してくれないようなので、必要なら指定する。
# 今回は特に使わないのでコメント
#        stylesheets=[
#           CSS('/static/css/something.css')
#        ],
    )

    response = HttpResponse(pdf_file, content_type='application/pdf')
# ダウンロードした時のファイル名称を設定。
    response['Content-Disposition'] = 'filename="scoringsheet.pdf"'

    return response

urls.py

urlpatterns = [
# weasyprint
    path('generate/pdf/', views.generate_pdf, name='generate_pdf'),
]
試しにPDF化実行すると、各種エラー発生

urlsに書いたアドレスにアクセス。
ローカルサーバーだと、以下のようなアドレスです。
http://127.0.0.1:8000/generate/pdf/

エラーが出ました。

django OSError: no library called "cairo" was found

cairoってのが無いようなので、サーバーを落としてHomebrewでインストールします。

brew install python3 cairo pango gdk-pixbuf libffi

再度サーバー起動。またエラー。

no library called "libcairo-2" was found
cannot load library 'libcairo.so': dlopen(libcairo.so, 2): image not found
cannot load library 'libcairo.2.dylib': dlopen(libcairo.2.dylib, 2): image not found
cannot load library 'libcairo-2.dll': dlopen(libcairo-2.dll, 2): image not found

なんか、色々ネットで対処法を探しているとpython3系ならpip3でインストールしないといけない。らしいので再度weasyprintをインストール。

pip3 install WeasyPrint

必要かどうか不明ですが、ここでもう一度cairoをインストール。

brew install cairo

また別のエラーが出ました。
もしかしたら、前にも出ていたかもしれませんがここで気がつきました。

Error: The following formula
  [#<Dependency: "python@3.8" []>, #<Options: []>]
cannot be installed as binary package and must be built from source.
Install the Command Line Tools:
  xcode-select --install

xcodeがバーチャル環境にちゃんと入っていないのかな?
よくわかりませんが、サーバーを落としてxcodeをインストール。

xcode-select --install

再度サーバー起動。またエラー。

    raise OSError(msg)
OSError: cannot load library 'pango-1.0': dlopen(pango-1.0, 2): image not found.  Additionally, ctypes.util.find_library() did not manage to locate a library called 'pango-1.0'

pangoってのが無いようなので、サーバー落としてpangoをインストール。

brew install pango

サーバー再起動。成功です。

PDF出力テスト

PDF出力するURLにアドレスにアクセスして、PDF出力テストします。
派手に文字化けしてしまいました。
(Djangoのテンプレート画面)

f:id:te-tou:20200614144612p:plain
Django テンプレート
(weasyprintでPDF出力結果)
f:id:te-tou:20200614144752p:plain
weasyprint PDF出力結果

日本語と数字が全滅です。
HTMLにはちゃんと文字コード指定をしてるのですが、関係ないようです。
ちなみに改ページしても、ヘッダはページごとについてきたので安心しました。

今後の課題

まずは上記の文字化けをなんとかしないといけません。
それが出来たら、A4で横向き(landscape)出力設定をしたいです。
現状調べたところ、よくわからないです。

まとめ

weasyprintはインストールが一つでは済まないのが難点です。
ソース自体はサンプルコードが結構落ちているので、とりあえずはなんとかなります。
しかし、細かい不具合についての対処法はあまり無いように感じました。この辺りは結構努力が必要そうです。
最後に、Djangoのテンプレート通りに出力はしてくれない様なのでCSSはweasyprint用にCSSはちゃんと指定した方が良いみたいです。

ついでに

(上記のソースでは関係ありませんが)ソースの書き方によっては、日本語があるとユニコードエラーが出るようなのでoutput.nameを以下のように変更。

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb5 in position 10: invalid start byte
output = open(output.name, 'r')
↓fix
output = open(output.name, 'rb')




www.facebook.com
www.youtube.com

ホンダビートPP1 オーバーフェンダー化(計画2・アーチ上げの費用とか)

 

 

続きです。

www.te-tou.tokyo

 

先日入手した汎用オバフェンをのこぎりで切り落として、ざっくりサイズを合わせてみました。

f:id:te-tou:20200607225044j:plain

ホンダビート  オーバーフェンダー

ちなみに取り付け前は、こんな感じ。

f:id:te-tou:20200607225159j:plain

ホンダビート  ノーマルフェンダー

やっぱり迫力が違います。

f:id:te-tou:20200607225421j:plain

ホンダビート  オーバーフェンダー

f:id:te-tou:20200607225454j:plain

ホンダビート  オーバーフェンダー

どんな感じで取り付けるかを考えつつ、フェンダーのアーチ上げをする場合の費用を近所の評判が良さそうな板金修理屋さんに聞きに行きました。

ずばり、リヤフェンダー2個で約10万円。

内訳を簡単に見ると、

  • アーチ上げのためのフェンダーカット
  • 切った部分にシール材を注入して処理
  • 汎用フェンダーの塗装
  • オバフェン取り付け などなど

内容としてはかなりきれいに仕上げてくれそうな感じでした。

しかし、10万かー。

あとは、構造変更とか諸々の手続き・ホイールとかワイドスペーサーとかの費用などなど。手間と時間はかかるけど、やっただけの満足感を得られるとは思います。

だがしかし、心は折れ始めました。

アーチ上げしないで取り付けられないかとは考えていますが、車高調はこれで車高一番高い位置っぽいからタイヤを外に出すと間違いなくフェンダーに当たっちゃいます。

タイヤを小さくするかなーとか考えつつ、なんかさっくり解決したいです。

 

 

www.youtube.com

www.facebook.com

ホンダビートPP1 オーバーフェンダー化(計画)

 

かねてから、ホンダビート の車幅の狭さがかっこ悪いと常々思ってました。

しかし、車幅を変更するということは構造変更やらなんやら結構一大事です。

 

とまあ、長年色々考えていましたが汎用オーバーフェンダー買いました。

f:id:te-tou:20200606222151j:plain

汎用オーバーフェンダー

たしか、片側8cm。

 

実際の取り付けとかは今は考えず、とりあえず位置合わせしてみます。

f:id:te-tou:20200606223304j:plain

ホンダビート オーバーフェンダー

でかいな。

長い部分は切り落とすとして、やっぱりこうした方がカッコいい。

f:id:te-tou:20200606223639j:plain

ホンダビート  オーバーフェンダー

なかなかの迫力です。

しかし、でかい。

f:id:te-tou:20200606223812j:plain

ホンダビート

真横から見ると、元のフェンダーが見えてしまってます。

タイヤもどうせやるならツライチにしたいので、深リムホイールに変えるかワイドスペーサーをかませるか対応すると思うのでフェンダーのアーチ上げが必要です。

流石にアーチ上げは専門の板金屋さんに頼まないとですが、どれくらい予算がかかるか不明です。

f:id:te-tou:20200606224318j:plain

ホンダビート  オーバーフェンダー

これくらいワイドな方がカッコ良いです。

さてさて、どうするか。

 

汎用オバフェン自体は7千円しないくらいでしたが、実際の取り付けとかタイヤ周りをいじるとなると結構予算がかかりそうなので悩みます。

 

 

www.youtube.com

www.facebook.com

Django win10にanacondaインストールしてDjangoの開発環境をつくる。

 

タイトルがカタカナと横文字が多くてバカっぽいですが、win10でanacondaからのDjango開発環境作成の走り書きメモです。

anacondaインストール

まずは、anacondaインストール。

www.anaconda.com

このリンクの下部に環境(macとかwinとかbitとか)ごとのダウンローダがあるので、PCにダウンロードしてからexeを開くとインストール開始。

途中選択画面で迷ったら、ググればなんとかなります。

pathを通す

コマンドプロンプトを使って、どこのディレクトリにいても呼び出せるようにパスを通しておきます。

 

まず、win10で環境変数を開きます。

win10はコントロールパネルの開き方からしてわかりづらいのですが、画面左下の「ここに入力して検索」に「環境変数」と入力すると候補を出してくれます。

f:id:te-tou:20200523161352p:plain

win10 環境変数の開き方

下図のように「環境変数」を押下し、pathを選択して「編集」を押下。

f:id:te-tou:20200523162840p:plain

win10にanacondaの環境変数追加

下記のパスを新規に追加します。

  • C:\Users\(ユーザー名)\Anaconda3
  • C:\Users\(ユーザー名)\Anaconda3\Scripts
  • C:\Users\(ユーザー名)\Anaconda3\Library\bin
コマンドプロンプトで確認

pythonのバージョン情報を確認してみて、ちゃんと表示されたら良しとします。

  • python -V

f:id:te-tou:20200523165223p:plain

python -V

ついでにPower shellで使えるようにするには、PsCondaEnvが必要らしいです。

下記コマンドでインストールできます。

  • conda install -n root -c pscondaenvs pscondaenvs
仮想環境作成

仮想環境がなんたるかは、とりあえず開発環境をいれる「箱」を作るイメージだとおもっています。

たくさん作れるし、いらないのは消せるし。

ちゃんと箱を分けておけば、箱の中が混ざり合わなくて変なことも起こらないし程度に認識してます。

 

なので、ざっくり「箱」の名前を決めます。⇒とりあえす「test」にしときます。

コマンドプロンプトで下記のコマンドを打って仮想環境を作成します。

  • conda create -n test ⇒「test」の部分は任意の名称をいれます。

途中で「proceed?」と聞かれるので、「y」で返します。

仮想環境確認

下記のコマンドで環境情報を確認できます。

  • conda info -e

f:id:te-tou:20200523174904p:plain

conda info -e

「test」という環境が作成されました。

環境のアクティベート

下記のコマンドで仮想環境をアクティベートします。

  • activate test ⇒「test」の個所は作成した仮想環境名

f:id:te-tou:20200523174935p:plain

仮想環境をactivate

activate コマンドを打つと、(test)というのがプロンプトの先頭に表示されます。

 

ここでもう一度、仮想環境確認コマンド。

  • conda info -e

f:id:te-tou:20200523233043p:plain

conda info -e after activation

アクティベートした「test」環境に*(アスタリスク)マークがつきました。

 

ちなみにアクティベートをやめるときは、以下のコマンドで。

  • deactivate

先頭の(test)が消えます。

 仮想環境にDjangoをインストール

仮想環境の中にDjango開発ができる材料をインストールします。

  • conda install django

f:id:te-tou:20200523233731p:plain

conda install django

「proceed」は「y」でenter。

そうすると、目盛りが動いてさいごに「done」が表示されてインストールが終わります。

 

インストールを確認するために、コマンド打ちます。

  • conda list

f:id:te-tou:20200523234413p:plain

conda list after django install

リストが表示され、Djangoがインストールされてることがわかりました。

 

ここまでで、win10にanacondaインストールしてDjangoの開発環境をつくりました。

まとめ

windowsでの環境構築はめんどくさい。

 

 

www.youtube.com

www.facebook.com

Rakuten UN-LIMITを契約(めっちゃWi-Fiがダメダメなので)

 

2020年4月以降、クラウドsimを使った容量無制限サービスの「めっちゃWi-Fi」が使い物にならないくらい速度が出なくなってしまいました。

www.te-tou.tokyo

なので、巷で話題の楽天アンリミットを契約しました。

東京にいるなら、23区内を拠点としている場合は現状かなり良い契約だと思います。楽天ポイントもたまるし。

Wi-Fiルーター的に使えれば良いと考えています。

折角なので、ちょっと興味があった楽天ミニも合わせて購入しました。

 

早速、Rakuten UN-LIMITの公式サイトから申し込み。

 

楽天ミニ到着

申し込みからちょうど2日で荷物が自宅に届きました。

f:id:te-tou:20200511004234j:plain

Rakuten MINI

アンドロイド端末のRakuten MINIはeSIMにのみ対応しているので、simカードはありません。

f:id:te-tou:20200511004945j:plain

内包物は至ってシンプルです。

コネクタはUSB~C。

f:id:te-tou:20200511004455j:plain

Rakuten MINI と iPhone11 大きさ比較

Rakuten MINIに新色としてクリムゾンレッドとかありましたが、手持ちの物と統一感があった方が洒落てるかと思い白を選択しました。

とりあえず箱から出して、iPhone11との大きさ比較。

Rakuten MINIかなり小さいです。あと、この白は高級感があって良いです。

逆に、iPhone11は大きい。私は手があまり大きくないので片手で使うのは結構しんどいです。

設定

眺め終わったら、電源を入れて設定してゆきます。

f:id:te-tou:20200511005617j:plain

Rakuten MINI 手順書

基本的に手順書に沿って操作してゆけば良いので簡単です。

いろんな人がこの設定方法を記事にしているので、迷ってもなんとかなります。

しかし、仕方ないことですが「〜アプリに〜を許可しますか」で必ず「はい」を選択しないといけないのはやや抵抗があります。しかし、仕方ない。

 

eSIMの設定も記憶に残らないくらい簡単に出来ました。楽天モバイルのアプリの最新版をダウンロードして、どこかのボタンを一つ押す程度の作業でした。

これで楽天モバイルのネットワークにつながります。

速度(世田谷区付近)

速度がどんなもんか見てみます。(20200510.世田谷区付近)

f:id:te-tou:20200511010247j:plain

Rakuten UN-LIMIT速度

結構良い方だと思います。

時によっては50Mbpsくらい出たりもします。

 

翻って、めっちゃWi-Fi。(20200510.世田谷区付近)

 f:id:te-tou:20200511010434p:plain

もはや死亡レベルです。yahooのトップ画面表示するのもやっとです。

これで毎月料金取られるのには不満です。改善するまで無料にしてくれないかな。

悪口を言わないことにはおさまりません。

まとめ

ともあれ、楽天アンリミットが開通しました。

ただ、立川周辺の都下を寝城にしているので対応エリアが早く広がって欲しいです。

 

Rakuten MINIの使用感については、小さいながらもそんなに不便では無いです。

おそらくqwerキーは相当使いづらいとは思いますが、フリック入力で日本語打つ分には全然問題ないです。

当面は「ポータブルプレイヤー兼、Wi-Fiルーター + α」みたいな感じで使えば良いと思ってます。電話機としては優秀ですが、これひとつメイン端末にするには勇気が必要です。

ついでに付与ポイント予定

オンラインから手続きすると楽天ポイントがジャンジャン貯まりますね。

SMSアクティベーションを正しく行うことがポイント付与の条件みたいです。

network.mobile.rakuten.co.jp

期間内にちゃんと手続きすると還元されるポイントはざっと下記の通りです。(多分間違っていないと思います。)

  • オンライン手続き→3000p
  • 申し込み事務手数料ポイントで返還→3300p
  • 楽天ミニ購入+プランセット→5000p
  • 紹介コード適応(楽天モバイルID)→2000p(紹介した人は3000p)

上記合計で13,300ポイントですね。端末買ったり事務手数料払ったりするんで現金は使いますが、これだけポイントバックされればかなりお得な気がします。

紹介コード適応は手続きの途中で入力する必要があるのですが、よく注意しないと見逃してしまいそうな場所にあるので事前にどこに入力するか調べてから手続きした方が良さそうです。

 

 

www.facebook.com

www.youtube.com

Django ListViewで2つ以上の小数点を持つフィールドの計算結果を求める。(テンプレートタグ)





Djangoのテンプレートで四則演算を行うときの方法です。
単純にテンプレート上でA+Bみたいなことが出来なかったので調べました。

整数の計算であれば、前回の記事で書いた「項目1|add:項目2」のように書けば足し算してくれます。
www.te-tou.tokyo
しかし、小数点の計算計算は出来ません。

まさか四則演算でハマるとは思ってもいませんでしたが、これを実現するために関数を使う必要があるようです。
なので、「テンプレートタグ」というものを使います。

テンプレートフィルタとテンプレートタグの違い

ざくっと受けられる引数に違いがあるようです。

  • テンプレートフィルタ(引数2つまで)
  • テンプレートタグ(引数2つ以上使用可能)

今回は引数を2つ以上使いたいので、テンプレートタグを使用します。

環境
  • python : 3系
  • Django : version 3.0.2
用例

scoreというアプリがあるとします。テスト点数を入力してゆくアプリです。
そしてその入力したテストの点数の合計値をListViewで表示させます。
英語とかの点数に小数点はなかなかないとは思いますが、細かいことは考えず。
modelsの「scoreテーブル」に以下のフィールドを持っている。

  • 名前
  • 英語得点
  • 国語得点
  • 数学得点
  • 理科得点
  • 社会得点

ListViewで「英・国・数・理・社」の合計点数を表示する。

関数を作る(テンプレートタグ)

まず、templatetagsというフォルダをtemplatesと同じ階層に作成します。
そのフォルダの中にテンプレートタグ(関数)ファイルを作成します。
名前はなんでも良いので、sum_points.pyとします。
省略
┗score
 ┗templates
 ┗templatetags ←フォルダを作る。
  ┗sum_points.py ←テンプレートタグファイルを作成する。

sum_points.pyの中身

from django import template
#テンプレートライブラリに登録する
register = template.Library()
@register.simple_tag

#関数名はpoints
#引数5つを受け取り、足し算した結果を返り値へ送る
def points(value1, value2, value3, value4, value5):
    return value1 + value2 + value3 + value4 + value5
ソース

models

from django.db import model

class Score(models.Model)
          name = models.CharField(
                 verbose_name = '名',    
                 max_length=10,
           )
           #得点はフロート型で小数点以下を入力可能とする。
           engPoint = models.FloatField(
                 verbose_name='英語',
                 default=0.0
           )
           natPoint = models.FloatField(
                 verbose_name='国語',
                 default=0.0
           )
           matPoint = models.FloatField(
                 verbose_name='数学',
                 default=0.0
           )
           sciPoint = models.FloatField(
                 verbose_name='理科',
                 default=0.0
           )
           socPoint = models.FloatField(
                 verbose_name='社会',
                 default=0.0
           )

views

from django.shortcuts import render

class ScoreListView(ListView):
          model = Score,
          template_name = 'score/score_list.html'  #使用するテンプレートを指定

urls

from django.contrib import admin
from django.urls import path

from name.views import ScoreListView

urlpatterns = [
          path('score', ScoreListView.as_view(), name="score"),
          path('admin/', admin.site.urls),

いつも通りパスを通して。

template (score_list.html)

<div>
    {% for score in object_list %}
    <tr>
        <!-- リストの一番左にNoをカウントアップして自動的につける -->
        <td>{{ forloop.counter }}</td>

        <td>{{ score.name }}</td>

        <!-- 英国数理社の得点を入力 -->
        <td>{{ score.engPoint }}</td>
        <td>{{ score.natPoint }}</td>
        <td>{{ score.matPoint }}</td>
        <td>{{ score.sciPoint }}</td>
        <td>{{ score.socPoint }}</td>

        <!--  合計得点を表示する -->
        {% points score.engPoint score.natPoint score.matPoint score.sciPoint score.socPoint %}
        <!--  関数名・引数1・引数2・引数3・引数4・引数5 を書くと、結果が返り値として表示される -->
    </tr>
    {%  endfor %}
</div>
まとめ

これで同一レコードの四則演算が出来ます。
querysetだとテーブルに対してフィルタとかかけるような感じなので、用途が違いますね。もしかしたら、querysetとかでもっと賢い方法があるかもしれませんが。




www.facebook.com
www.youtube.com

Django templateで変数を使う(with ~ as 変数名)ついでに文字連結




先日、Djangoでviewsからtemplateへcontextを使って変数を渡す方法を書きました。
www.te-tou.tokyo

検索の仕方が悪いのか、単に理解不足なのかDjangoでの変数の使い方が分かりづらかったので備忘です。
熟知している人が書いてる説明は要領がとてもよく書いてあり、痒いところに手が届かない感じです。

今回はtemplateだけで変数を使う方法です。

環境
  • python : 3系
  • Django : version 3.0.2
用例

前回の記事と同じ用例とします。

ex)use case
かなりどうでも良い思いつきの用例です。

細かいことは考えず、
今回nemeアプリというのを作ってテーブル項目(テーブル名:FullName)に氏名を持っているとします。
ついでだから、「つのだ☆ひろ」みたいに氏名の間に☆を入れようと思いつきました。
じゃあ、引数に☆を持たせて実装しよう。という流れです。

ソース

models

from django.db import model

class FullName(models.Model)
          firstName = models.CharField(
                 verbose_name = '名',    #太郎
                 max_length=10,
           )
           familyName = models.CharField(
                 verbose_name = '氏',    #テスト
                 max_length=10,
           )

views

from django.shortcuts import render

class FullNameListView(ListView):
          model = FullName,
          template_name = 'name/fullname_list.html'  #使用するテンプレートを指定

viwsで変数を書く場合は、ここにget_context~みたいのを書きました。

urls

from django.contrib import admin
from django.urls import path

from name.views import FullNameListView

urlpatterns = [
          path('fullname', FullNameListView.as_view(), name="fullname"),
          path('admin/', admin.site.urls),

いつも通りパスを通して。

template (fullname_list.html)

{% with  FullName.familyName|add:"☆"|add:FullName.firstName as NAMAE %}
    <div class="fullname">
         {{NAMAE}}
    </div>
{% endwith %}

これにより、変数「NAMAE」には「テスト☆太郎」が代入されます。
そして、templateに{{NAMAE}}と書けば「テスト☆太郎」が表示されます。

まとめ

{% with ~%} から {% endwith %} の間で指定した変数が有効になる模様。
上記例では、
{% with テーブル項目|add:"リテラル文字"|add:テーブル項目 as 変数名%}という記述で、「~|add:~」で文字連結をしています。

addは項目が数字項目の場合は、足し算となる。(ただし、整数として処理される。)
例えば、
X=1, Y=3 という項目の場合、「X|add:Y as ans」と書けば{{ ans }}には4という結果が代入されます。
しかし、
X=1.5, Y=3 という項目の場合、「X|add:Y as ans」と書くと{{ ans }}の結果は4となります。(あくまで整数)
小数点の計算をしたい場合は、カスタムタグを定義するようです。(数字を足し算ではなく文字連結したい場合も同様)
今の悩みは、2つ以上の引数を持つカスタムタグをどう作るかです。
→解決したので、下記の記事をどうぞ。
www.te-tou.tokyo




www.facebook.com
www.youtube.com