はてなブログでコードを表記する方法って多分あるんだけどそれはのちのち調べるとして質問、コメント、投票のすべてを紐づけるためのmodels.pyの構成はこうだった。
確信があったわけではなく何度も試行錯誤して見つけている。
下が正解。
import datetime
from django.db import models
from django.utils import timezone
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
date_limit = models.DateTimeField('公開期限', default = datetime.datetime.now )
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
was_published_recently.admin_order_field = 'pub_date'
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'
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
class Choice_Comment(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE, null=True)
choice = models.ForeignKey(Choice, on_delete=models.CASCADE)
choice_comment_text = models.TextField('コメント(未入力可)',blank=True, null=True)
投票とコメントは同時に行う
ここの最大のポイントはここ。
question = models.ForeignKey(Question, on_delete=models.CASCADE, null=True)
choice = models.ForeignKey(Choice, on_delete=models.CASCADE)
questionはfieldsの非表示だがchoiceは表示させる。
さらに
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
とあるように質問の中の選択肢choice_textとvoteは同じmodelの中に書く。
ちなみに
def __str__(self):
return self.choice_text
がないと選択肢がすべてchoice_text(8)等の表記になってしまう。
何を言いたいかというと
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
で選択肢をユーザーに選択させる。
しかしこのままでは選択肢とコメントは紐つかないので
class Choice_Comment(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE, null=True)
choice = models.ForeignKey(Choice, on_delete=models.CASCADE)
choice_comment_text = models.TextField('コメント(未入力可)',blank=True, null=True)
choice_comment_textでユーザーが投稿したコメントを質問と選択した選択肢に同時に紐つける。
そのためのviews.pyがこうだ
def vote(request, question_id):
form = ChoiceCommentForm(request.POST or None)
question = get_object_or_404(Question, pk=question_id)
if request.method == 'POST':
if form.is_valid():
selected_choice= question.choice_set.get(pk=request.POST['choice'])
selected_choice.votes += 1
selected_choice.save()
choice_comment = form.save(commit=False) # コメントはDBに保存されていません
choice_comment.question = question
choice_comment.save() # ここでDBに保存
return redirect('polls:results', pk=question_id)
context = {
'question': question,
'form': form,
'error_message': "投票内容を選んでください",
}
return render(request, 'polls/detail.html', context)
ここに至るまで何度も何度もトライ&エラーを繰り返し書籍を読み、udemyの講座を見返してようやく実現した。
classでも作れるかと思ったが関数で書くほうが分かりやすくて楽ということで何とか答えにたどり着けた。
これでついに基本的なロジックは完成。ついにやった!
ただし細かい問題は残っていた。
空欄のコメントも表示されてしまう。
選択肢のフィルタリングが出来ずに他の質問の選択肢もすべて掲載されてしまう。
選択肢の最初に---という表記があり消せない。
質問の公開期限の設定
等々だ。結局フィルタリングのところはまだロジックを理解しきれていないのだがこのころになると自己解決力もついてきてそれなりに一人で解決できるようになってきた。
なにしろ最大の山場はここだった。多分ここまでで20日以上かけている。
細かい問題はあるがあと少しなのだ。