THUMBS SHIFT→

このブログは主に親指シフトを用いて書かれています

django で自分で作ったファイルをダウンロードさせる

どういうときの話?

例えばユーザーの入力によって動的にファイルを作り、そのファイルをModelのデータベースに保存1させつつ、ユーザーにダウンロードさせたいとき

下準備

# @settings.py
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
MEDIA_URL = '/media/'

参考

設定 | Django documentation | Django

Djangoで、ファイルダウンロード | NARITO BLOG

スラッシュの過不足があったりするとエラーが出るので注意。

# @urls.py
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    # ... the rest of your URLconf goes here ...
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

これはユーザーだけじゃなくて、自分でアップロードする場合にも必要。これは開発時の設定なので注意

参考

静的ファイル (画像、JavaScript、CSS など) を管理する | Django documentation | Django

# @models.py
from django.db import models

class FileModel(models.Model):
    file = models.FileField(upload_to='files/')

足りない所は想像力で補ってください。

ファイルをModelに保存する

from django.core.files.base import ContentFile
from .models import FileModel

string = 'this is sample file content'
myfile = FileModel()
content = ContentFile(string)
myfile.file.save('file_name', content)

参考

モデルフィールドリファレンス | Django documentation | Django

こうするとDBに登録されるのでフィルターとかソートとかして取り出せる(はず)。

同名のファイル名で上書きすると、suffixが付いたファイルが新たに作成されて、そちらがDBの指すファイルの実体となる。もとのファイルが削除されるわけではない。

html側は、

<a href="{{ uploadfile.file.url }}" download="{{ uploadfile.file.name }}">{{ uploadfile }}</a>

のようにdwonload属性を使うのが手軽でいいと思う。

参考 

Djangoで、ファイルダウンロード | NARITO BLOG


  1. この言い方は正しくないが

migrate-exblog 2.0.0をリリースしました

github.com

知らない人向けに説明すると、これはエキサイトブログにははてなブログのようなエクスポート機能が無いので、スクレイプして他のブログに移行できる形式に変換するプログラムです。

今までの、単体テストも無くて、パラメータの設定の仕方も気持ち悪い仕様から大幅に変更しました。

今まで全部の投稿をとってくるのに、/m2005-01-01みたいな月ごとの投稿一覧ページを全部試してとってきてたんですけど、なんと/m1900-01-01/に全ての月ごとのアーカイブページのリストがあったんで、そこからとってくるようにしました。このおかけでだいぶ高速化できました。あ、ちなみに一回サーバーにリスエスト送ったら0.5秒休むようにしてます。

これで大体開発終了ですかね。まぁカード型のデザインとか、独特なスキン使ってるとエラー出るんですけど、正直使う人もいないしそこまでやってもなって感じです。

今後は勉強のためにdjangoでWebアプリ化でもしてみようかなと思います。

ほんとにこの開発を通じて良い経験になりました。使ってもらえるのが一番うれしいけどどうしたら有名になるんだろうか。宣伝?

pythonプロフェッショナルプログラミングを(大体)読んだ

読んだ。kindleで買ったら800円くらいポイントが付いてきたのでラッキー。

個人開発で限界を感じてる人におすすめ。

Pythonプロフェッショナルプログラミング 第3版

Pythonプロフェッショナルプログラミング 第3版

最近個人で開発しているが、pythonのパッケージ化とか、開発のお作法とか、テストの書き方とか、gitの使い方とか、なんにもわからなかったので買ったけどほんとに欲しいものが書いてあった。

前も調べたことが合ったんだけど、その時は旧版で、gitじゃなくてmercurialとかちょこちょこ微妙なトコが合ったが、改訂してからはgitになったのでとても使いやすくなった。

入門書みたいに、listのメソッドにはsortやappendなどがあって〜〜と全部書いている訳じゃないのが特に良かった。こういう機能があって、こういうように運用するといいですよ。詳しくはドキュメント見てくださいね。さっきの例えで言うとlist型があって、一気に値を保持できますよ。こういうときに使うと良くて、詳しいメソッドはドキュメントをみてね。みたいな。

こういう体裁を採ってるおかげで、実際に開発で使うときのノウハウが沢山載ってるのがとても良い。詳しいとこまで全部説明してたらいくら紙面があってもたりないしね。

一番重点的に読んだのはパッケージ化の所。ちょうどやりたかったしね。次点でテストかな。逆にチケット管理とか、チームで開発するときに重要になるようなところは流し読みしただけ。内容が濃いのでこの本を全部マスターすれば結構すごいプログラマになるんじゃないか?え?ならない?そう・・・

次はテストの実装とか、djangoを使ったwebアプリ化とかをやってみる。

pythonで画像をbase64エンコードしてimg タグに埋め込む

import base64 as bs
from pathlib import Path
IMG_TAG = '<img src="data:image/jpg;base64,{base64}"/><br>'
image_path = Path('path/to/somewhere')

def make_base64_tag(image_path):
    with image_path.open('rb') as f:
        enc = bs.b64encode(f.read())
        enc = enc.decode()
    return IMG_TAG.format(base64=enc)

以上です。

エキサイトブログをMovable Type形式でエクスポートするツールを公開しました

github.com

 タイトルの通りです。エキサイトブログにあった部活のブログを移行する際にまさかのエクスポート機能がないという糞仕様だったので自分で書いたのを改変して公開しました。なにがムカつくってインポート機能はあるところだよな。そういうとこやぞ。 FC2を経由してエクスポートはできるっぽいけどこれがあるから自前で実装していないのだろうか。ちなみになんでFC2経由でエクスポートできるのに自作したのかというと自分でやりたかったからです。あとFC2は新規にブログ作ってから1週間はエクスポートできない。(別のサイトも移行したんだけどそのとき使ったスクリプトが流用できそうだったのもある。)  これからmovable typeを利用したソフトを開発する人向けに言っとくと(いるのか?)これmovable typeのドキュメントになってる。movable typeという名前がブログの出力フォーマットと、CMS両方につかわれているので探すのがとても面倒くさい。なんかバージョンが4で、古いかもしれないけど知らん。

 スクレイピングして記事の内容集めてきてるんですけどまじでエキサイトブログのhtmlが汚すぎて内容の選別が大変でした。部活のブログのhtmlはまさかのtableタグで記事を管理してるのでほんとに汚い。htmlのデザインは全然詳しくないけどこれが良くないことだというのはわかる。

 まぁ糞仕様とかなんだかんだ言ってるけど、そのおかげでスキルが上がったのには感謝してる。綺麗だったらぱっと取ってきて終わりだっただろうし。この公開を通してgithubの使い方とかお作法とかpythonデバッグとかjupyterの使いどころとか学べたので楽しかった。

 READMEにも書いてあるけど現在はタイトル、本文、投稿日時のエクスポートしか対応してません。コメントとかカテゴリとかにも対応するかどうかは皆さんの反応にかかってます。正直自分はもう使わないので開発のモチベがない。反響があればやろうと思います。Webアプリケーション化とかやっても面白そう。

 みんなもこのツールを使って微妙にデザインのダサさが漂うエキサイトブログから脱出して、モダンなはてなブログに移行しよう!

 これ見て雇ってくれる企業とかねぇかな(期待)。

シン・ゴジラ の感想

いつかは見ようと思っていたシンゴジラをやっとみた。色々思うところはあったけど楽しかった。

思うところのなかでも特に言いたいことが「はよエヴァ作れ」ね。これは各所で言われているので俺からはこれ以上はいわない。

全編通して、ずっとエヴァヤシマ作戦を見てる感じだった。BGMもヤシマ作戦の使われてたしね。ヤシマ作戦のBGM汎用性高すぎだろ。割と普通にTVのBGMでも流れてるし。新劇場版のエヴァのCD全部持ってる俺としては他のBGMもめっちゃ好みだった、と思ってスタッフ調べてみたら音楽は鷺巣さんなのね。通りで聞いたことあるテイストだと思った。庵野はよシンエヴァ作れ。

ひたすら会議見させられるけどヤシマ作戦大好きな俺としてはもう会議が面白かった。会議室の全体をとりながらバックで「〜〜を確認」「目標〜〜しました」「〜〜を関係各所に通達」とか情報がながれこんでくるのが好き。エヴァでオペレーターたちがやってたあれ。最後の作戦行動よりむしろ会議が好き。ほんとにエヴァに毒されてしまったと自分でも思う。はよエヴァ作れ。

会議の内容も(グダグダさ方面での)リアリティがすごいあって、形式を踏まないと行動できない日本の民主主義ってのがひしひしと感じられる。射線上に民間人がでてきて射撃の可否を問うシーンで上司から上司へ電話が回されるシーンがあるんだけど、いや現場の報告ぐらい直接聞けるようにしとけよとか、そういう細かいところで現実感がでてくる。

見る前から「内閣総辞職ビーム」って聞いてたから今か今かと待ってたんだけどあれだったのか。なんかもっと間接的なもの(ビームによる不祥事とか)で総辞職かと思ったらもろ直撃で笑った。そういや憲法にそんな文言あったなぁ。試験では全く使わなかった知識がこういうとこで活きてくると楽しい。

まぁ肝心の作戦部分には賛否あるみたいだけどまぁ良いんじゃね。なんとかして(アルマゲドンの削岩機みたいな)もので穴開けて体に直接打ち込むシナリオにすればいいかとおもった。とはいえ俺はそういうもんだと思って楽しく見てました。楽しんだもの勝ち。

結論としてはエヴァ作れです。おしまい。

pythonではてなAPIを使って記事を投稿する

色々認証方式があるけど一番簡単なBASIC認証でやる

template = """<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:app="http://www.w3.org/2007/app">
<title>{title}</title>
<author><name>name</name></author>
<content type="text/plain">{body}</content>
 <updated>{date}</updated>
 <app:control>
     <app:draft>no</app:draft>
 </app:control>
 </entry>
"""
# ここでインデントするとprintで出力したときにおかしくなる。
# templateの{title}, {body}, {date}にそれぞれ値を入れる。
# nameは変えたりして試してみたけど特に違いがわからなかったのでそのままにしてる。
# dateの書式はdatetime.datetime.strftime('%Y-%m-%dT%H:%M:%S')でいける

uri = 'https://blog.hatena.ne.jp/{hatena_id}/{blog_id}/atom/entry'

# このブログで言うとhatena_id = 'arark', blog_id = 'arark.hatenadiary.jp' (ドメイン名)

api_key = '<api_key>'  # 設定に書いてある

import requests
from requests.auth import HTTPBasicAuth

res = requests.post(uri, auth=HTTPBasicAuth(hatena_id, api_key), data=template)

これでOK

uri変えたりすれば他のAPIでも使えると思う

requestsでUnicodeEncodeErrorがでたけど何でも良いから送信したい時

python のrequestsの話です。

import requests
r = requests.post(url, data=str)
>> UnicodeEncodeError ...

となってしまった時は

r = requetsts.post(url, data=str.encode('utf-8', errors='ignore')

とすればよろしく無い文字を無視してPOSTしてくれる。

これは内部でstr.encode('utf-8')みたいに文字列をバイト列に変換しているためで、最初からdataにバイト列を渡しておけば起こらないのでignoreを指定して無理やりutf-8のバイト列にしている。

ignoreの他にも色々エラーハンドラがあって、 ここ で確認できる。

使用例はこっち

probikekit 利用記録

probikekitでracing zeroを買ったのでその履歴をここに貼っておく。f:id:arark:20181229154957p:plain

海外通販で注文したはいいものの待ち遠しすぎて一日に100回は確認する俺みたいな人はいると思うのでこれを参考にしてほしい。

まぁ感想としてはとにかく遅かった。まず発送26日って言ってるのに28日発送だからね。いや別に遅いのは良いんだよ。知ってて注文したし。でも26日っていってるのに待たされると気を揉むよね。ブラックフライデーで忙しいのもわかるけどね。

んでまぁ日本につくのも遅いよね。10日かかってるし。他のサイトで見たところによると5日とかで着いてるのもあったから5日で来るかな−とか期待しちゃうよね。いいけどね遅くても。

でも日本に来てからは早いって周りも言うし俺もそう思ってるから税関で4日待たされるのはちょっと意外だよね。二次検査(?)までされたみたいだから多分「おいおいホイールに8万とかまじかよ軽く自転車買えるぜwwww」みたいに笑われてたのかな。それとも値段が信じられなくて色々確認とかしてたのかな。

まぁなんだかんだで最寄りの郵便局まで着いて、到着予定日14日(郵便局着いた当日)って書いてあった時は期待して即家帰って関税用意したよね。来なかったけど。次の日の夜7時に来たね。だったら14日って書くなよって思ったけどね。

総じて「遅いのは良いけど期待させるな」って感想だね。みんなも海外通販ではあんまり期待しないで待とうね。

mezzanineのチュートリアル"A Mezzanine Tutorial, Take 2"の覚書

最近python製のCMS(wordpressみたいなもの)である"mezzanine"を勉強してた。日本語での情報が少ないので

Docs / Mezzanine / A Mezzanine Tutorial, Take 2 | Rod's Tech

このサイトを参考にしてたんだけど、解説不足や(おそらく)アップデートで現状に即して無いところがみつかったので気づいたところをかいてく。一通り読んだけど自分自身まだ全然mezzanineについてわかってないので参考程度に読んでください。

元サイトがやってることの流れ(多分)

俺はあまり英語読みたくないので必要なところだけ読もうとしたけど、前のpartで言ったこと使ったりするので同じことすると躓くとおもいます。 

part1

mezzanineのインストール。ブログの投稿ページをMarkdown記法で書けるようにする。

part2

ブログ記事内でコードハイライトを適用する。要らないと思ってここを飛ばすと後でわかんなくなる。(実体験)

part3

デフォルトのページをカスタムする。

part4

新しいページを作る。adminにmodelを追加する。ココらへんから俺の手に負えなくなってきたので覚書がなくなる。

part1

Pagedown, a Mezzanine Markdown Package

#####################
# PAGEDOWN SETTINGS #
#####################
RICHTEXT_WIDGET_CLASS = 'mezzanine_pagedown.widgets.PageDownWidget'
RICHTEXT_FILTER = 'mezzanine_pagedown.filters.custom'
RICHTEXT_FILTERS = (RICHTEXT_FILTER,)
PAGEDOWN_MARKDOWN_EXTENSIONS = ('extra','codehilite','toc')
RICHTEXT_FILTER_LEVEL = 3
PAGEDOWN_SERVER_SIDE_PREVIEW = True

をsettings.pyに追加する際、「RICHTEXT_FILTERSを変な書き方してるのはバグで、たぶん今は治ってると思うよ」と筆者は書いてるけど自分が試したところでは多分治ってないのでそのままコピペしてください。

urlpatterns = patterns("",
("^pagedown/", include(mezzanine_pagedown.urls)),

を置き換えろとあるが、このコードはアプデのせいかもう存在してないので20行目あたりにある

urlpatterns = i18n_patterns(
    # Change the admin prefix here to use an alternate URL for the
    # admin interface, which would be marginally more secure.
    url("^admin/", include(admin.site.urls)),
)

urlpatterns = i18n_patterns(
    # Change the admin prefix here to use an alternate URL for th
    # admin interface, which would be marginally more secure.
    url("^admin/", include(admin.site.urls)),
    url("^pagedown/", include(mezzanine_pagedown.urls)),
)

に置き換える。

part2

Generate Pygments css

python manage.py pygments_styles はエラー出るので python manage.py pygments_styles -h を使う。

python manage.py pygments_styles colorfulもエラーなので python manage.py pygments_styles --scheme colorfulを使う。このコマンドはCSSコードを生成するけど、それをどこに置くかが下の段落に書いてある。

part3

SEARCH_MODEL_CHOICES = []

はsettings.pyのどこかに書く。

Remove Left and Bottom Menus

{% page_menu "pages/menus/tree.html" %} はbase.html の106行目

{% page_menu "pages/menus/footer.html" %}はbase.htmlの135行目

<div class="span2 left">
to

<div class="span1 left">
and

<div class="span7 middle">
to

<div class="span8 middle">

とあるが検索かけてもこの部分がみつからなかったのでアプデで消えたと思われる。あとそもそもbody.htmlが消えてbase.htmlに統合されているので注意。おそらく上のdivタグは <div class="col-md-3 right"> にまとめられてて、実際ここのdivタグを全部取り除くと下の枠が消えるんだけど、これが良い方法なのかはわからん。

Make Home Page CMS Editable

"mezzanine.pages.views.page"

を""で囲むのを忘れないように。警告がでるので気になる人は一番上でimport mazzanineとでもすればいい。

While we're mucking with pages in the admin, clean out pages you don't want.

これはadmin>Pagesからできる。

以降は気が向いたら書く。何年後になるかは知らない。

part4