DreamerDreamのブログ

夢想家の夢です。〜揚げたてのモヤっとしたものをラフレシアと共に〜

Django奮闘記⑥最終章?ーそして伝説は生まれるー

 前回はテンプレートを使いました。

dreamerdream.hateblo.jp

 

参考チュートリアル、いよいよ4ページ目です。

はじめての Django アプリ作成、その 4 | Django documentation | Django

 

今回はフォームの書き方。

テンプレートで謎な部分もありますが、フォームが書けるとようやく僕の書きたい動的なページに近づきますのでサンプルを試していきます。

detail.htmlフォームを弄ります。

raspberrypi:~/dreamer $ nano polls/templates/polls/detail.html

テンプレートですね!

<h1>{{ question.question_text }}</h1>

{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}

<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
{% endfor %}
<input type="submit" value="Vote">
</form>

 

ラジオボタンを押した時にvalueにchoice.idを格納してPOSTするというフォームですね。

POSTリクエストに付随するクロス サイトリクエストフォージェリ攻撃に対抗する手段として{% csrf_token %}というDjangoのテンプレートタグを適用するのが良いそうです。(理由はよくわかりませんが)スゴイです!

raspberrypi:~/dreamer $ nano polls/views.py

をサンプル通りに変更します。

from django.http import HttpResponse, HttpResponseRedirect
from django.template import loader
from .models import Choice, Question
from django.http import Http404
from django.shortcuts import get_object_or_404, render
from django.urls import reverse

.........................(略)

def vote(request, question_id):
  question = get_object_or_404(Question, pk=question_id)
  try:
    selected_choice = question.choice_set.get(pk=request.POST['choice'])
  except (KeyError, Choice.DoesNotExist):
    # Redisplay the question voting form.
    return render(request, 'polls/detail.html', {
      'question': question,
      'error_message': "You didn't select a choice.",
    })
  else:
    selected_choice.votes += 1
    selected_choice.save()
    # Always return an HttpResponseRedirect after successfully dealing
    # with POST data. This prevents data from being posted twice if a
    # user hits the Back button.
    return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))

 

 

selected_choiceにPOSTで得られた値を格納、POSTデータに'choice'が無ければエラー処理、POSTされるとHttpResponseRedirectでresultsへリダイレクトする。

reverse関数は意味がよく解りません。

 

polls/views.pyのresults関数も書きます。

def results(request, question_id):
  question = get_object_or_404(Question, pk=question_id)
  return render(request, 'polls/results.html', {'question': question})

 

raspberrypi:~/dreamer $ nano polls/templates/polls/results.html

htmlテンプレートを書きます。

<h1>{{ question.question_text }}</h1>

<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>

<a href="{% url 'polls:detail' question.id %}">Vote again?</a>

 

整いました!

アクセスすると一覧が見えます(選択肢がテキトーすぎますが)

f:id:DreamerDream:20180904110512p:plain

選択するとvoteで投票できます!

f:id:DreamerDream:20180904110627p:plain

集計が見えるはずー

で?!!できませんっ!!ひえー

views.pyのエラーメッセージですね、

f:id:DreamerDream:20180904110650p:plain

何かがおかしいようです。

うーん、サーバーは機能してるし、voteページから動かないからvoteのエラーで間違い無いでしょう。

polls/views.pyのquestionをprint出力してみます。

def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
print(question)

voteすると

Question object (3)
[04/Sep/2018 11:40:15] "POST /polls/3/vote/ HTTP/1.1" 200 283

きちんと選択はされている様子。。うーん

わざとエラーを吐かせてみます。

f:id:DreamerDream:20180904114930p:plain

choiceってキーがないぞって怒られてます

f:id:DreamerDream:20180904114955p:plain

ブラウザにも同じエラーメッセージが出ました。

f:id:DreamerDream:20180904115017p:plain

おかしい、choiceのスペルミスもないし、

もっかい記事を見直してみると

ラウザで /polls/1/ を表示して投票してみましょう。

とある。が、こちらのアドレスは.polls/test/1/?おや?アドレスがおかしいのか?

f:id:DreamerDream:20180904121913p:plain

urls.pyを元に直してみる

f:id:DreamerDream:20180904122055p:plain

 

アカンのかーい!!

いったい’choice’はどこー??

request.POSTに含まれているようなので一覧を取得する方法を探ってみる。

フォームに入力された値を取得する - Django Tips

request.POST.lists()

で取得できるそうな。

f:id:DreamerDream:20180904124629p:plain

はい、わかんない。

じゃあ、こちらの方法で

Djangoで複数の値を持つPOSTデータを全て取得する方法

from django.utils import six
print(dict(six.iterlists(request.POST)) )

f:id:DreamerDream:20180904125515p:plain

はい、もっとわかんない。けどchoiceというキーが含まれていないことは確かっぽい。

 

まてまて!今気が付いたが、フォームでラジオボタンを設定していながら、ラジオボタンが表示されていない!?

テンプレートか?テンプレートの設定なのか??

何かがおかしいのは確かなんだけど、、、

f:id:DreamerDream:20180904132909p:plain

 

とりあえず、今までの読んだ所を見直してみることにする。

2ページ目のAPIで遊んでみるの項目は関係無さそうと思って読み飛ばしていたので、読んでみるとmodelsが弄ってあるところを発見!!

はじめての Django アプリ作成、その2 | Django documentation | Django

これかなあ?その通りに弄って保存してみる

from django.db import models
from django.utils import timezone

# Create your models here.

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    def __str__(self):
        return self.question_text

    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)
    def __str__(self):
        return self.choice_text

 

 結果

・・・撃沈

 

ダメ。。

もうダメっぽ

 

諦めずにもう一度プロジェクトの生成からやり直しましたが、、、何故だぁ〜〜〜同じとこで無理ぃ。。。

ということで、第一回の奮闘は見事に敗北してしまいましたorz。。。。か?(聞くな!)

 「Djangoなら何でも出来そうだぜっ!」と意気込んでトライしたのですが、それは僕の中では伝説となってしまうのでしょうか?

 

次回、復活なるか?

dreamerdream.hateblo.jp