読者です 読者をやめる 読者になる 読者になる

cloverrose's blog

Python, Machine learning, Emacs, CI/CD, Webアプリなど

Django Sprint 13.2 の経過報告 #djangoja

Django

チケット #13408 (Unpacking list/tuple in for loop should raise exception on unpacking if length is different) – Djangoに対応しようと思ったんだけど、無理そうだったので、そこまでの成果をまとめて後半戦に移ろうと思う。

チケットの概要は次のソースコードで再現できる。
ちなみに、Djangoは{{ var }}で渡されていないものを参照しても、エラーにならなくて、何も出力されないのが挙動。

# views.py
def test(request):
    points_3d = [(1,1,1), (2,2,0), ]
    return render_to_response('seiyu/test.html', {'points_3d': points_3d})
# test.html
here start
{% for x, y, z, w  in points_3d %}
  x={{ x }}, y={{ y }}, z={{ z }}, w = {{ w }}
  no probs :(
{% endfor %}
here end

# output ( browserの結果をコピペ)
here start x=1, y=1, z=1, w = no probs :( x=2, y=2, z=0, w = no probs :( here end

報告者の意図としては、以下のコードがエラーを発生させるように、エラーを出したほうがいいっていう感じ。
なので、{{ w }}部分はエラーにする必要はなくて、問題なのは、unpackで数が違う部分。

points_3d = [(1,2,3), (1,2,3)]
for x,y,z,w in points_3d:
    pass

ValueError: need more than 3 values to unpack

Timeline
カスタムフィルターは作ったことあったけど、カスタムタグはなかったので、TemplateのTagがどのように実装されているかを把握するために、テンプレートタグやフィルタを自作する — Django v1.0 documentationを読みました。

大きな流れは以下の2フェーズ
1. パースしてNodeインスタンスを生成
2. Nodeインスタンスの.renderメソッドを呼び出して出力


そして、読んでいくと、少し雲行きが怪しくなって来ました。

render() は TemplateSyntaxError やその他の例外を送出してはな りません。フィルタと同様、失敗は暗黙のうちに処理されるようにせねばな りません

render() should never raise TemplateSyntaxError or any other exception

なるほど、出力フェーズではエラーを出さずに、パースフェーズでエラー出さないといけない。
が、パースフェーズでは、obj_listの値がわからないのでできない(何を今更)

{% for x in obj_list %}

調べるためにいじった部分を晒す

django/template/defaulttags.py
class ForNode(Node):
def do_for(parser, token): # ここは結構読んだのでメモとか入れたので載せとく defaulttags.py
django/template/base.py
class Variable(object):