TRY AND ERROR

気になったこと、勉強したこと、その他雑記など色々メモしていきます。。Sometimes these posts will be written in English.,

Python3 with djangoでエクセルで文字化けしないcsvをダウンロードさせる

よくあるcsvダウンロード機能ですが、エクセルで開くことを想定して作らなければいけないケースが多々あると思います。
今回、エクセルで開いた時に日本語が文字化けしないcsvのダウンロード機能をpythonで書いてみます。
使っているフレームワークDjango

標準のcsvモジュールだとunicodeがサポートされていないとのことなので、unicodecsvを使います。
GitHub - jdunck/python-unicodecsv: Python2's stdlib csv module is nice, but it doesn't support unicode. This module is a drop-in replacement which *does*. If you prefer python 3's semantics but need support in py2, you probably want https://github.com/ryanhiebert/backports.csv

unicodecsvはpipでインストールできます。

pip install unicodecsv


基本的には標準のcsvモジュールと似ていますね。

from django.http import HttpResponse
import unicodecsv as csv

def csvdl(request):
    ret = HttpResponse(content_type="text/csv")
    ret["Content-Disposition"] = "attachment; filename=name.csv"
    w = csv.writer(ret, encoding='cp932')
    w.writerow(["あいう", "えお", ...])    
    return ret

encoding='cp932'を使えるところがミソ!!

Buttonタグで勝手にsubmitされる件

ハマった!!!

djangoajaxしようと思ってカリカリ書いてたら何度やっても画面のリロードが走る。
これはdjangoの変な仕様だと決めつけてcsrfらへんを必死に調べたけど手がかりなし。
かれこれ1時間半くらい経った時に、ふと昔同じような件でハマったのを思い出す。

原因はButtonタグの仕様で、Buttonタグはdefaultでtype="submit"になるとのこと。

type="button"(汎用ボタン)にすることで無事ajaxが走る。


Buttonクリック時にeventを受け取ってevent.preventDefault();でデフォのsubmitをキャンセルしておけば、
type="submit"でも同じ動きになる。(type="submit"にする意味ないけど)

ってか2ヶ月位前にこの仕様でハマったにもかかわらず、同じことを繰り返してた
自分にめちゃくちゃ腹が立ったというお話でした。。。

django、疑ってすまん。

PythonのAnacondaってどうなん??

気軽にscrap and buildできるPython3の汎用開発環境を作りたいと思ってDockerfileを書いてみました。

dockerfile-for-python-proto/Dockerfile at master · kentaro-a/dockerfile-for-python-proto · GitHub


Pythonあまり触ったことないのでモジュルやら何やら詳しくないのですが、
Python-3.5.1をソースからインストールしてpip,pandasその他を入れるみたいなことをやってる。。


Tensorflow触ってみたいので↑から作ったコンテナでインストールしようとしたものの、
依存モジュール絡みでもんのすごく面倒くさいっぽい。

いろいろ調べていくうちにAnacondaというプラットフォームを発見。
どうやら分析寄りの環境を簡単に構築できるらしい、、、というかPythonの環境管理全般いけるみたい。

pipであくせくするよりもこれで管理したほうがいいんじゃね?と思ったんですが、どうなんでしょうか。。

まあとにかくAnaconda試してみようと思います。

WordPressのAMPプラグインで/ampが真っ白になった件

WordPressのAMPプラグインを入れると一発でAMP化できるらしい、
という噂を聞いて早速試す、、、無事撃沈。
若干ハマったのでメモします。

・使ったプラグイン
AMP — WordPress Plugins


こちらのブログを参考にしたのですが、自分の環境でうまくいきませんでした。
プラグイン公式サイトのFAQに同じ質問が挙がっていたものの、未解決でした。。
WordPressのプラグインでブログをAMP対応にしてみた | 海外SEO情報ブログ



あれこれ調べた結果、サーバにphp-xmlがインストールされていなかったため、
プラグインのモジュール内でDomDocumentクラスが使えずに落ちていたことが原因でした。

WordpressのconfigでdebugモードをONにしてエラーを出してみると、
DomDocumentクラスが使えないみたいなメッセージがしっかりと出てました。

php-xmlをインストールしてapache再起動で解決。

yum -y install php-xml
service httpd restart


ちなみに、AMPプラグインでは現状投稿ページしかAMP対応できないそうです。
AMPのバリデートエラーもブラウザの機能でチェックできるようです。
詳しくはこちらで紹介されています。
検証!AMPに沿ったマークアップとエラーチェックの方法をご紹介! | サクラサクLABO公式ブログ



ヤレヤレ。。

mysqlでtinyintがbooleanになる件

mysqlでtinyint(1)を指定したカラムのデータをcakephp3のモジュールで取得した際に、booleanとして扱われて困った。。

mysqlのバージョンは5.6.27

cakeのバグか?とも思ったんですが、リファレンスを見てみるとちゃんと書いてあった!

・BOOL、BOOLEAN
These types are synonyms for TINYINT(1). A value of zero is considered false. Nonzero values are considered true:

MySQL :: MySQL 5.6 Reference Manual :: 11.1.1 Numeric Type Overview

mysqlではbooleanはtinyint(1)のシノニムであり、0はfalse、0以外はtrueとして評価するとのことなので、cakeはtinyint(1)の値をbooleanに変換して処理してしまうようです。
ただ、実際にtinyint(1)には-128~127の整数値を入れられるので、ハマってしまう人も多いのではないでしょうか。

PHP7三項式まわりが快適すぎる

PHP7の三項演算あたりを本格的に使ってみましたが、快適すぎてやばいです!

あるkeyが存在するかどうかわからない配列をマージするような場合、
いちいちisset()しなくてよくなった!!

array_merge(
    $a['key'] ?? [],
    $b['key'] ?? [],
    $c['key'] ?? [],
    $d['key'] ?? []
);


isset地獄にみなさん1度はハマったことがあると思いますが、
PHP7だとスッキリしますね。

【Ruby】ChatworkAPI for Ruby

前回、ChatworkAPIクラスのPHP版を公開しましたが、今回Ruby版も作りました。

class Chatwork

	# イニシャライズ
	# apiToken: 自身のAPIトークン
	def initialize(apiToken)
		tokenHeaderKey = "X-ChatWorkToken: "
		@apiToken = apiToken										# APIトークン
		@reqHeader = "X-ChatWorkToken: #{@apiToken}"				# リクエストヘッダ
		@room = getRooms();        									# ルームID
	end


	# ルーム一覧取得
	def getRooms()
		ret = {}
		uri = URI.parse("https://api.chatwork.com/v1/rooms");
		
		# httpクラス
		http = Net::HTTP.new(uri.host, uri.port)
		http.use_ssl = true
		http.verify_mode = OpenSSL::SSL::VERIFY_NONE
		
		# httpリクエスト情報オブジェクト
		request = Net::HTTP::Get.new(uri.request_uri)
		request.add_field("X-ChatWorkToken", @apiToken)
		
		# httpレスポンス
		response = http.request(request)

		# ルーム名:ルームIDのハッシュにする
		JSON.parse(response.body).each{|data|
			ret[data["name"]] = data["room_id"]
		}
		return ret

	end
	private:getRooms


	# ルーム名からルームIDを取得する
	# roomName: ルーム名
	def getRoomID(roomName)
		return @room[roomName]
	end


	# メッセージを送る
	# roomid: ルームID
	# msg: メッセージ
	def sendMessage(roomid, msg)
		uri = URI.parse("https://api.chatwork.com/v1/rooms/#{roomid}/messages");

		# httpクラス
		http = Net::HTTP.new(uri.host, uri.port)
		http.use_ssl = true
		http.verify_mode = OpenSSL::SSL::VERIFY_NONE

		# httpリクエスト情報オブジェクト
		request = Net::HTTP::Post.new(uri.request_uri)
		request.set_form_data({'body'=>msg})
		request.add_field("X-ChatWorkToken", @apiToken)
		
		# ChatworkAPIにpostする
		http.request(request)
	end

end


使い方も前回同様にAPIトークンを渡してnewし、getRoomIDにメッセージを送信したいルーム名を渡してルームIDを取得、
sendMessageでメッセージを送るといった流れです。

GitHubリポジトリこちら


最低限の機能しか実装してませんのでカスタマイズしてみてくださいm(_ _)m