Django – Tutorial4 – フォーム

フォームの配置

このページはDjangoのDocumentation、Writing your first Django app, part 4に対応している。

detailページの機能

チュートリアルのテンプレートのところで作成したindexページでは、データベースのquestionテーブルに保存されたQuestionデータの一覧が表示される。

各Questionデータのリンクをクリックすると、polls.viewsモジュールのdetail関数にルーティングされ、detailテンプレートが呼ばれてページが表示される。

現状でこのページでは、"You're looking at question 1."のようにクリックしたQuestionデータのidを含むテキストが表示されるだけ。

ここでdetailページに以下のような機能を持たせる。

  • クリックしたQuestionデータのquestion_textを表示する
  • そのQuestionデータに関連付けられた(すなわちその回答選択肢となる)Choiceデータ群を、ラジオボタンとともに表示する
  • Voteボタンを押すと、選択した回答のidが送信される

id送信後の振る舞いについては後に実装することとして、ここでは上の機能をテンプレートで実装していく。

コードの変更

pollsアプリケーションのdetailテンプレートを以下の内容に変更する。

テンプレートがビューから受け取る変数

questionオブジェクトとerror_message(テキスト)が渡されることを想定している(上記コードのL4, 6, 8)。

form要素のactionとmethod

form要素のオプション設定は以下の通り。

  • actionの呼び出し先はpollsアプリケーションのname='vote'ルート→vote関数で、questionデータのidをURLパラメーターで渡す
  • メソッドはPOST

csrf_tokenタグ

form要素内の最初にCSRF/XSRF (cross-site request forgery)対策として{% csrf_token %}を置いている。form要素にこのタグを置かないと、Djangoによりアクセス禁止のエラーとなる。

qustion_textの表示

ビューから受け取ったquestionオブジェクトのquestion_textプロパティーの内容をh1要素として表示させる。

エラー表示

ビューの処理でエラーになった場合error_message変数が定義されることを前提としている。DTLのifタグにより、error_messageがセットされているときはこれが表示され、選択肢とラジオボタンが表示される。

選択肢の表示

questionデータに対する選択肢はChoiceデータが関連付けられていて、そのコレクションはDTLのドット検索によりquestion.choice_set.allで得られる。

フォームでは、このコレクションの要素(各Choiceデータ)をDTLのforタグで1つずつ取出している。そして、各choiceについてラジオボタンとラベルテキストを生成している。

ラジオボタンの属性は以下のとおり。

name=”choice”
すべての選択肢に同じname属性を適用してグループ化している。
id=”choice{{ forloop.counter }}”
label要素で参照するidで、先頭から連番でchoice1, choice2, …のような値となる。forloop.counterDTLのforタグの変数で、ループカウンターの値が得られる。
value=”{{ choice.id }}”
選択されたラジオボタンに対応する値で、Choiceデータのidが充てられる。このidによって、データベース上の指定したデータが得られる。

このテンプレートがレンダリングされたときのHTMLは以下のとおり。valueの値が1, 2, 4となっているが、データの削除・追加によってAUTO_INCREMENTの値は必ずしも連続にならない。一方、forloop.counterを利用したidの数字部分は連番となっている。

ここでindexページのQuestionデータのうち"What's up?"をクリックすると、レンダリングされたdetail.htmlにより以下のページが表示される。

この段階でVoteボタンを押すと、polls.viewsモジュールのvote関数にルーティングされるが、この段階では”You’re voting on question 1.”とだけ表示される。

vote関数の実装

vote関数での処理

ここではフォームのアクション先であるvote関数の処理を実装する。処理内容は、Questionの持つ選択肢のうちditailページで選択・送信されたChoiceデータのvoteカウンターを1つ増やしてデータベースを変更するというもの。

コード

vote関数の内容を以下のように変更する。

モジュールのインポート

パッケージ先頭でHttpResponseRedirectモジュールをインポートしている。このモジュールは、URLconfで定義したルート名とパラメーターを与えてレスポンスを返す。

またChoiceモデルを扱うために、Questionに加えてChoiceモジュールもインポートしている。

Questionの取得

フォームのaction属性で、Questionデータのidをクエリーパラメーターで渡すようになっていて、vote関数の引数でこれを受け取る。

そのidQuestionデータを取得し、存在しなければ404エラーとなる。

投票登録:try~except~elseブロック

このブロックで、Questionデータに対する選択肢をデータベースから取得し、エラーならエラー処理をし、成功したならその選択肢の得票数を1つ増やす。詳細は以下の通り。

try節

try節では、前段で得られたQuestionデータの選択肢Coiceデータのうちフォームで選択されたものを取得する。

  • getメソッドでpkPOST['choice']に等しいデータを取り出している
  • POST['choice']はフォームにおいてname='choice'INPUT要素から得られるvalue属性の内容
  • 今回のフォームではラジオボタンのグループが'choice'であり、POST['choice']から選択されたボタンのvalue属性の値が得られる
  • フォームではvalue={{ choice.id }}としているので、この値は選択された選択肢に対応するChoiceデータのidの値

except節

except節では、引数で指定したKeyErrorChoice.DoesNotExistの2つの例外をキャッチしている。いずれかの例外が発生した場合に、現在処理中のQuestionデータを与えて元のdetailページを表示させるが、このときエラーメッセージをセットしているのでこれも表示される。

KeyErrorPOST['choice']でデータを取り出すときに'choice'というキーが存在しない場合に発生する。このような状況は次の場合に発生する。

  • 選択肢を持たないQuestionデータに対してVoteボタンを押した場合(今回の例の場合question_text"Hou're you doing?"のデータ)
  • HTMLのラジオボタンのname属性が改ざんされた場合

Choice.DoesNotExistの方は、getメソッドで条件に合うデータがデータベース上にないときに発生する。ただ今回のコードでは、DB上のデータが取得できない場合はget_object_or_404により404エラーへと飛ぶようになっているので、ここでDoesNotExist例外は発火しないのではないか。

else節

else節はtry節の処理が正常終了した場合に実行される。今回の場合、フォームで選択された選択肢のChoiceデータが無事取得できたことになるので、データベース上の得票数カウンターを1つ増やして投票結果表示のresultページにリダイレクトする。

得票数のカウントアップは簡単で、取得済みのデータについて以下を実行。

ただしこれはデータベースからメモリー上に取得されたデータを変更しただけなので、変更後のデータをデータベースに登録する必要がある。

最後に戻り値としてHttpResponseRedirectを返している。これはDjangoに特化したものではなく、HTTPでの処理の標準的な手筋。

動作確認

 

折れ線と曲線の近似誤差

円弧の長さと弦の長さの差

半径r、内角θの円弧の長さLa

(1)    \begin{equation*} L_a = r \theta \end{equation*}

これに対する弦の長さは

(2)    \begin{align*} L_c &= \sqrt {r^2 + r^2 - 2 r^2 \cos \theta} \\ &= r \sqrt {2 (1 - cos \theta)} \end{align*}

ここでLcLaの比を計算すると、rを含まないθのみの関数となる。

(3)    \begin{equation*} \frac{L_c}{L_a} = \frac{\sqrt {2 ( 1 - \cos \theta ) }}{\theta} \end{equation*}

θを度単位としてこの比をグラフにすると以下のようになる。

角度変化が30度弱で誤差が2%程度、20度で0.5%程度、10度になるとかなり誤差は小さくなっている。

そこでこの付近の誤差を計算してみる。

角度 5度 10度 15度 20度 25度 30度
Lc/La 0.9997 0.9987 0.9971 0.9949 0.9921 0.9886
誤差 0.03% 0.13% 0.29% 0.51% 0.79% 1.14%

道路線形の例

道路ネットワークのリンクを折れ線で近似する場合の誤差を考える。

式((3)の誤差率の計算結果から、円弧の内角が20~30度程度以内であれば、弧と弦の長さの差はかなり小さくなりそうだと予想される。

そこで角度に対して曲線半径rを掛けて曲線部の道路の長さを計算し、さらに誤差から曲線の道路の長さと直線で近似した長さの差を計算してみる。

角度 rad 弧長(60) 弧長(710) 差分(60) 差分(710)
5 0.08727 5.236m 61.959m 1.7mm 1.9cm
10 0.17453 10.472m 123.918m 1.3cm 15.7cm
15 0.26180 15.708m 185.878m 4.5cm 53cm
20 0.34907 20.944m 247.837m 10.6cm 1.26m
25 0.43633 26.180m 309.796m 20.7cm 2.45m
30 0.52360 31.416m 371.755m 35.8cm 4.23m

ネットワークデータの用途により、許容される誤差が決まり、必要な補完点の密度が変わってくる。

たとえばメートル単位の経路案内であれば10cmオーダーの誤差は許容され、交差点での停止になると数cmなど。後者の様にミクロなコントロールや自動運転に直接データを活用する場合は、数cm程度以下の精度が必要となると想定される。

 

Django – render/redirect/HttpResponseなど

概要

ビュー関数/ビュークラスのメソッドはHttpResponseクラスやその派生クラスのインスタンスを戻り値として、テンプレートをレンダリングしたり指定したURLに遷移する。

この戻り値の与え方としては、HttpResponseやその派生クラスのインスタンスを直接与える方法と、django.shortcutsで定義された関数(render、 redirect)を使う方法がある。

HttpResponseはレスポンスボディ―を指定して表示。ショートカットのrenderは引数にテンプレートファイルを指定し、それを表示する。

URLを指定したリダイレクトには、HttpResponseRedirectやショートカットのrenderを使う。

レンダリング

HttpResponse

HttpResponsedjango.httpパッケージのモジュールで、ヘッダーや内容などを持つHTTPレスポンスのクラス。インスタンス生成時に引数にテキストを指定したテキストがレスポンスボディ―になり、直接表示される。

テキストのほか、イテレーターやファイルも指定できる。

render

renderdjango.shortcutsパッケージのモジュールで、指定したテンプレートファイルの内容をHttpRequestインスタンスとして返す。

テンプレートファイルに加えて、テンプレートに引き渡す変数コンテキストも指定できる。

リダイレクト

HttpResponseRedirect

HttpResponseRedirectdjango.httpパッケージのモジュールで、指定したURLに遷移するためのHTTPレスポンスのインスタンスを生成する。

HttpResponseRedirectHttpResponseRedirectBaseを継承し、HttpResponseRedirectBaseHttpResponseを継承している。

ビュー関数/メソッドの中で、URLを引数に与えてHttpResponseRedirectのインスタンスを生成し、戻り値にそのインスタンスを渡すことで、指定したURLにリダイレクトされる。

引数のURLは以下のように与えることができる。

  • ホスト名を含む絶対URL
  • アプリケーション名から始まるサブディレクトリーによる相対URL
  • urls.pypath関数で設定したルート名をreverse関数の引数に与えた戻り値(ルート名を直接与えることはできない)

redirect

redirectはdjango.shortcutsパッケージのモジュールで、指定したURLにリダイレクトするためのHTTPレスポンのためのスインスタンスを返す。

redirectは関数として定義され、デフォルトではHttpResponseRedirectのインスタンスを返すが、引数にpermanent=Trueを設定すると、HttpResponsePermanentRedirectのインスタンスを返す(このクラスは301ステータスを返す)。

redirectHttpResponseRedirectを返す際、resolve_url関数を介していて、reverse関数を使わず直接ルート名を渡すことができる。

 

Django – HttpResponse

概要

HttpResponsedjango.httpパッケージにあり、HTTPリクエストに対してサーバーからクライアントに返されるHTTPレスポンスを表すクラス。

Django Documentation – Request and response objects

プロパティー

HttpResponseは以下のプロパティーを持つ(一部記載)。

status_code
ステータスコードの値
headers
ヘッダーの各項目の内容
content
レスポンスボディの内容。バイトストリング。
charset
文字コード名
reason_phrase
ステータスコードのフレーズ。RFCに準拠。

インスタンス生成例

まずモジュールをインポートし、文字列を渡してHttpResponseインスタンスを生成。インスタンス表現や型を確認。

ステータスコードとステータスフレーズを確認。

ヘッダーとそのうちの文字コードを確認。

ボディー部の確認。バイトストリングになっている。

 

Django – フォームデータ

概要

テンプレートのフォームで入力・送信されたデータをビューで受け取って処理する方法の基本。

ビュー関数/メソッドの引数(たとえばrequest)のPOST配列でフォームのINPUT要素のname属性値を指定して値を取得する。

request.POST['name属性値']

実装例

2つのページへのルーティング

urls.pyinputページとresultページへのルーティングを設定。inputページにフォームを置き、そこから送信されたデータをresultページで表示することとする。

DTLのurlタグを使うため、各ルートにname引数でルート名を付けている。

inputページのためのビュー

ルート名formtest:inputでルーティングされるview関数。単にinput.htmlテンプレートをレンダリングしている。

input.htmlテンプレート

input.htmlテンプレート。フォームには、textタイプのINPUT要素と、3つの選択肢を持つradioタイプのINPUT要素群が置かれている。

  • textタイプのINPUT要素のname属性はinput_test
  • radioタイプの3つのINPUT要素のname属性はradio_choiceで値はpinebambooplum

送信ボタンが押されると、methodで指定したURLに飛ぶが、ここではurls.pyで定義したformtest:resultに飛ぶようにDTLのurlタグを使っている。

resultビュー

フォームからの送信に対してviews.pyresult関数が呼ばれる。result.htmlテンプレートにcontext辞書を介して2つの変数input_textradio_choiceを渡している。

  • input_text変数には、name='input_text'で指定されたテキストの内容がrequest.POST['input_text']で取得されて代入される
  • radio_choice変数には、name='radio_choice'で指定されたラジオボタンのうち選択されたもののvalue値がrequest.POST[‘radio_choice’]で取得され、これに対応する文字列が代入される

result.htmlテンプレート

resultテンプレートでは、ビューのcontextで設定された変数の内容を表示する。

 

Django – DTL – URL

概要

urls.pyでURLパターンからビューへのルーティングを指定しただけの場合、テンプレートでそのルーティングを使うにはURLを直書きしなければならない。

これに対して、urls.pyのURLパターンを任意に変更しても影響が及ばないようにするには、DTLのurlタグを使う。

URLハードコーティングの場合

たとえばmyappアプリケーションのmainページからsubページへのリンクを貼りたいとする。

アプリケーションのurls.pyは以下のようになっているとする。

ルーティングされたビュー関数が以下のように書かれているとする。

レンダリングされるテンプレートでURLをハードコーティングした場合は以下のようになる。

main.html

sub.html

このときのURL指定と各ページの対応は以下のとおり。

  • [DOMAIN]/myapp/ → views.main → main.html
  • [DOMAIN]/myapp/sub → views.sub → sub.html

URLハードコーティングの問題

urls.py中のpath関数のURLのパターンを任意に変化させると、各テンプレート中のURLを全て見直さなければならない。これの影響を及ぼさせないようにしたい。

urls.pyでのname指定

urls.py中、抽象化したいpath関数にname引数を追加する。この場合はsubページへのpath関数を以下のように変更。

そして、subページへのURLの代わりにDTLのurlタグを使い、その引数にurls.pynameで指定した値を与える。

アプリケーションを指定する場合

異なるアプリケーションでnameに指定したい値が重複する場合、[app_name]:[path_name]で指定できるようにする。

path()関数でnameを指定する際、urls.pyの冒頭でapp_name変数にアプリケーション名の文字列を指定しておく。

そして、DTLのurlタグの引数にapp_nameで指定した値を加える。

まとめ

グローバルなパス名の場合

  1. urls.pypath関数にname引数でパス名を指定
  2. URLの代わりに{% url 'パス名' %}を指定

アプリケーションローカルなパス名の場合

  1. urls.pypath関数にname引数でパス名を指定
  2. urls.pyの冒頭でapp_name='アプリケーション名'を記述
  3. URLの代わりに{% url 'アプリケーション名:パス名' %}を指定

 

Django – クラスベースビューの基本

概要

Djangoのビューを実装するのに、関数で書く方法と、Viewクラスやその派生クラスを継承して必要なメソッドをオーバーライドする方法がある。

Djangoのオーソドックスな書き方ではクラスベースビューのListViewなどを利用し、コード量を減らすことが推奨されている。

ここでは関数による方法とViewクラスの継承クラスによる方法の2つを比較する。

基本形

テンプレートの準備

ビューからパラメーターを受け取り、単にそれを表示するテンプレートを準備する。ここではviewtestというアプリケーションを想定し、準備するテンプレートファイルはindex.htmlとする。

関数によるビューの実装

views.pyの記述

アプリケーションディレクトリー下のviews.pyファイルに、indexビューを関数で定義する。ビューではテンプレートに渡すパラメーターを文字列'Hello!'としている。

urls.pyの記述

アプリケーションのサブディレクトリーfunctionから、同じアプリケーションのindexビューへのルーティングを定義する。この例の場合localhost:8000/viewtest/functionのようにURLを指定し、ブラウザーでアクセスすることになる。

ここでサーバー起動状態でブラウザーに先のURLを指定すると、ブラウザーに以下のように表示される。

関数ビューの場合、GETを含むリクエストに対してurls.pyに従ってビューが呼び出され、その内容が実行される。

クラスベースビューによる実装

関数によるビューと同じ処理をクラスベースのビューで実装してみる。ここでは比較のために、関数ビューのコードを残してクラスベースビューのコードを追加していく。

views.pyの記述

クラスベースのビューは、Viewクラスやその派生クラス(ListViewなど)を継承し、getpostなどのリクエストに対応したメソッドを記述する。ここではGETリクエストにのみ反応させるため、getメソッドを実装している。

Viewクラスではgetメソッドは定義されていないが、Viewの派生クラスでGETメソッドでのリクエストがあるとViewクラスのhandlerが実行され、View.get()が実行される。そして派生クラスでget()を定義しているとこれがオーバーライドされたメソッドとして実行される。

参考:Django ViewではHttpメソッド名の関数を定義することができる

urls.pyの記述

クラスベースビューによるメソッドが呼び出されるようにアプリケーションのurls.pypath関数を追加する。

関数ベースの場合はpath関数の第2引数に関数表現のビューモジュールを指定したが、クラスベースの場合はIndexViewの親クラスViewas_view()メソッドを指定している。as_view()メソッドは内部関数view()を通してdispatchメソッドを返すので、結局パスが解決されるとdispatchメソッドが呼び出されることになる。

ここでサーバー起動状態でlocalhost:8000/viewtest/classなどとURLを指定すると、ブラウザーに以下のように表示される。

URLパラメーターを含む場合

関数によるビューの実装

urls.pyの記述

URLパラメーターを含む場合、URLパターンに型名やパラメーター名を入れる。

views.pyの記述

ルーティングで記述したパラメーター名をビュー関数の引数に指定し、これをテンプレートに渡す。

ここでサーバー起動状態でlocalhost:8000/viewtest/function/1などとURLを指定すると、ブラウザーに以下のように表示される。

クラスベースによる実装

urls.pyの記述

URLパターンにURLパラメーターを記述する方法は関数の場合と同じ。クラスベースビューの場合はas_viewメソッドの実行結果を渡す。

views.pyの記述

クラスベースビューの場合、getなどのメソッドの引数にパラメーターを指定する。引数の指定パターンは関数の場合と同じ。

ここでサーバー起動状態でlocalhost:8000/viewtest/class/2などとURLを指定すると、ブラウザーに以下のように表示される。

GET/POST処理

関数によるビューの実装

テンプレートの準備

GETで表示されるページにフォームを追加し、送信先をfunctionサブディレクトリー、メソッドをPOSTとする。

urls.pyの記述

今回のindexテンプレートはGET、POST両方のリクエストから呼び出されるため、functionサブディレクトリーのルーティング1つ。

views.pyの記述

リクエストメソッドの違いはrequest.methodの文字列で判定して処理を分ける。GETリクエストの場合は1つ目のifブロックが実行され、テンプレートに文字列'GET!'が渡される。またPOSTリクエストの場合は2つ目のifブロックが実行され、テンプレートには文字列'POST!'が渡される。

ここでサーバー起動状態でlocalhost:8000/viewtest/functionなどとURLを指定すると、views.index関数でGETに対応したifブロックが実行され、ブラウザーに以下のようにGET!と表示される。

このページで「送信」ボタンを押すと、今度はviews.index関数でPOSTに対応したifブロックが実行され、ブラウザーにPOST!と表示される。

クラスベースによる実装

テンプレートファイルの準備

POSTに対する処理を関数の場合と分けるため、送信先のURLのサブディレクトリーをclassとする。

urls.pyの記述

GET/POSTに関わらず、classサブディレクトリーでのリクエストを受け取った場合には、IndexViewクラス(のインスタンス)に処理を渡すように定義。

views.pyの記述

ルーティングで

ここでサーバー起動状態でlocalhost:8000/viewtest/classなどとURLを指定すると、views.IndexViewクラスでオーバーライドしたgetメソッドが実行され、ブラウザーに以下のように表示される。

このページで「送信」ボタンを押すと、今度はviews.IndexViewクラスでオーバーライドしたpostメソッドが実行され、ブラウザーに以下のように表示される。

クラスベースビューの基本のまとめ

要点

基本のクラスベースビューの要点は以下のとおり。

  • Viewクラスを継承したクラスを定義
  • GETやPOSTなどに対応したメソッドを定義
  • ルーティングでは、継承先のクラスの.as_view()メソッドを渡す

views.pyの記述

  • django.views.genericパッケージのViewモジュールをインポート
  • Viewクラスを継承したクラスを定義
  • getメソッド、postメソッドなどを定義
    • 第1引数はself
    • 第2引数はrequest
    • パラメーターがあればそれ以降
  • getメソッドの記述内容は、関数ベースの場合の内容と同じ
    • たとえばrender(request, 'target_page')

urls.pyの記述

  • urlpatterns属性のpath関数の第2引数でビュークラスを指定し、このときas_viewメソッドを指定する
    • たとえばpath('sub_dir', views_dir.MyViewClass.as_view())

 

古事記~土地~伊賦夜坂

概要

黄泉の国の伊邪那美神から伊邪那岐神が逃げおおせた場所(黄泉平坂)。黄泉の国と現世との境。

伊賦夜坂

国道9号から脇に入るとこのような案内がある。この案内に沿って車で入っていける。

その先に車を数台停められるくらいの平場がある。

黄泉平坂に関する説明。左には伊邪那岐神・伊邪那美神から神倭伊波礼毘古命(神武天皇)に至る簡単な系図が書かれている。

駐車場所から一段高いところに小径があり、このような石柱の門があった。このあたりで、静かだが軽く張り詰めたような雰囲気が漂う。

その先にある大岩。これが黄泉の国との境のようだ。

大岩の間からそっと先に進むとさらに狭い小径があるが、その先は細くなって林の中へ消えている。先へ歩を進めるのは憚られた。

戻ったところに木があり、立札によるとこれが伊邪那岐神を救った桃ノ木とのこと。伊邪那岐が桃に対して「汝(なれ)、吾(あれ)を助けしが如く、葦原中国に有らゆるうつしき青人草の、苦しき瀬に落ちて、患(うれ)へ惚(なや)むときに助くべし」と告げ、意冨加牟豆美命(おおかむずみのみこと)の名を与えたとある。

宣伝看板。伊邪那美命を祭った揖夜神社や、この場所が映画の題材になった場所であることなどが紹介されていた。

梅雨入り前、晴れて少し蒸し暑い日だったが、たまたま他にこの場所を尋ねる人もなく、独特の雰囲気が漂っていた。古来の土地を訪ねるのに、他の人の有無・多寡はその印象に影響を与えるのかもしれない。

 

 

古事記~土地~天岩戸神社・天安河原

概要

西宮と東宮の2つがあり、西宮で天照大御神が須佐之男命の乱行を恐れて隠れた岩戸を遥拝できる。

西宮の少し先に天安河原宮があり、そこで思兼神を中心に八百萬神が、岩戸から天照大神を連れ戻す策を相談したとされる。

神社

天岩戸神社の鳥居。想像していたよりもシンプル。

神社本殿。この脇に待合休憩所があり、30分ごとに神職の方に天の岩戸の遥拝所まで案内していただける。

天の岩戸の遥拝所。岩戸は撮影禁止。川向うに洞穴があり入口には半分閉じかけた岩壁があった。注連縄(しめなわ)に右から七・五・三の紙垂(しで)が下がっていた。

境内にある招霊木(おがたまのき)。天鈿女命(アメノウズメノミコト)がこの木の枝を持って踊ったと言われる。

神社由来。御祭神は天照大神で、手力男命(タヂカラオノミコト)と天鈿女命が合祀されている。

神社で時折見かける鶏。ここでも幾羽かいた。

天安河原宮

天岩戸神社西宮の上流側、車道から入っていく道がある。

渓谷の脇、細い道を歩いていく。

天安河はもう少し開けたイメージだったが、深山幽谷の雰囲気。

ここが天安河原。洞窟があるのは意外だった。古事記の話はそっちのけでみんな石を積んでいる。県の観光ポスターにそんな写真が載っているので仕方ないが、そんなセンスに興ざめ。ここでも紙垂が右から七・五・三となっている。

八百萬神が集まるにはちょっと狭い。小さく化身したのかも?