request.POSTにデータを追加したけど、これって……

request.POST をいじりたい

動機

以下のようなフィールドを持つフォームを作った。 fields = ('title', 'category_id', 'contents', 'tag', 'valid', 'author')

これはブログの記事を作るためのフォームで、author (記事の投稿者)は自動でログインしているユーザのオブジェクトを代入したい。テンプレート内にこれを表示してしまうと、自由に投稿者を操作できてしまう。それだとアカウント制の意味がない。なので、テンプレートにauthor のフォームは表示しない。

しかし、POSTされた情報をviewsで処理するときform.save() をすると「author がないよ」とエラーが返ってくるので(当たり前)views内で別途authorrequest.POSTに追加する必要があった。

追加してみる

ここで安直にrequest.POST['author'] = 'ジャスティン・ビーバー' と代入しようとするとエラーが返ってくる。request.POST はイミュータブルだから代入できないよ。というエラーが。どうしたものかと調べてみると2つの解決策を見つけた。

解決策その1 copy()

ひとつはcopy() でごっそりコピーする方法。

req = request.POST.copy()

これでコピーしてreq['author'] = 'ビル・ゲイツ' とすればちゃんと追加される。めでたしめでたし。

解決策その2 ミュータブルにする

もうひとつは、イミュータブルならミュータブルにすればいいじゃない。というやり方。

request.POST._mutable = True

これでrequest.POSTがミュータブルになって追加することができる。処理が終わったら再びイミュータブルにするのも忘れない。

request.POST._mutable = False

変数を追加しなくていいからこっちを採用した。が……

が……Django軽犯罪法違反な気がする

そもそもイミュータブルなのにはきっと何かしらの理由がある。それをいじって無理やりデータを追加するのはかなり行儀が悪い気がする。あんまり良い気分はしなかった。だから他の方法でなんとか解決しようとしたが、苦肉の策でこうなってしまった。何か別のやり方を調べねば。それかこういう状況に陥らない設計を考えるか。

反省室

というわけでrequst.POST に修正を加えることについて少しディグってみた。

stackoverflow.com

stackoverflow.com

やっぱりrequest.POST._mutable = True を推奨している人なんていませんね。禁断の果実に手を伸ばしたようです。反省。無理やりどうこうするようなやり方はよくない。うまいことやれる大人にならないと。明日リファクタリングだ!

P.S そしてこれを書いている真っ最中にレビューで「request.POST はいじらないよ!」というコメントをいただく。肝に銘じます。