ついに選択肢とコメントを紐つけた状態で投票ができるようになった。
つまり基本の部分は終了したことになる、ただまだ細かい部分が残っているのでそれを埋めていこうと思う。
選択肢のフィルタリング
投票する際にすべての選択肢が出現してしまうのでそこを修正。
質問に紐づいた選択肢のみを出現させる。
views.py
〜 class DetailView(ModelFormMixin, generic.DetailView): model = Question template_name = 'polls/detail.html' form_class = ChoiceCommentForm def get_queryset(self): return Question.objects.filter(pub_date__lte=timezone.now()) def dispatch(self, request, *args, **kwargs): self.target_question = get_object_or_404(Question, pk=kwargs['pk']) return super().dispatch(request, *args, **kwargs) def get_form_kwargs(self): kwargs = super().get_form_kwargs() kwargs['target_question'] = self.target_question return kwargs 〜
forms.py
〜 class ChoiceCommentForm(forms.ModelForm): choice = forms.ModelChoiceField( queryset=Choice.objects.all(), widget=forms.RadioSelect ) class Meta: model = Choice_Comment fields = "__all__" def __init__(self, *args, **kwargs): question = kwargs.pop('target_question', None) super().__init__(*args, **kwargs) # choice の選択肢を question に関係したものに絞り込む if question: self.fields['choice'].queryset = Choice.objects.filter(question=question) 〜
実はここのロジックだけはよくわかっていない他は大体読めるし意味も分かっているのだが、時間がかかってもいいので解決していきたい。 ・・・なにしろこれで質問に関連する選択肢だけを絞り込むことができた。 ただ選択肢---というものが常に表示される問題がまだある。 これは意外と簡単に解決することができた。
forms.py
〜 class ChoiceCommentForm(forms.ModelForm): choice = forms.ModelChoiceField( queryset=Choice.objects.all(), widget=forms.RadioSelect, empty_label=None ) class Meta: model = Choice_Comment fields = ('choice', 'choice_comment_text') def __init__(self, *args, **kwargs): question = kwargs.pop('target_question', None) super().__init__(*args, **kwargs) # choice の選択肢を question に関係したものに絞り込む if question: self.fields['choice'].queryset = Choice.objects.filter(question=question) for field in self.fields.values(): field.widget.attrs['class'] = 'input-group-sm' class Meta: model = Choice_Comment fields = "__all__" 〜
forms.pyのさらなる改造。 empty_label=None この一行だけでOKだった。 ちなみに widget=forms.RadioSelect, はフォームのラジオボタンへの変更。
続いては空欄のコメントを非表示にする。
views.py
〜 def commentlist(request, pk): question = get_object_or_404(Question, pk=pk) #コンテキストでpk渡さないとquestion.pkでリンクが飛ばない。 comment_filter = get_object_or_404(Question, pk=pk) context = { 'comment_ichiran':Choice_Comment.objects.filter(question=comment_filter).exclude(choice_comment_text__exact=""), 'question':question } return render(request, 'polls/comment_list.html', context) 〜
'comment_ichiran':Choice_Comment.objects.filter(question=comment_filter) これだけだと空欄のコメントも出現してしまうのでさらにフィルターをかける。 .exclude(choice_comment_text__exact=""), これを追加すればOK!!
ちなみにcontextにquestionを渡さないとurls.pyの<int:pk>に何も受け渡されなかった。 これを自己解決できたのは力が付いたんだなと感動した。最初は絶対理解できなかっただろうから。
公開期限の設定
さらに質問に公開期限を設定した。 modelsに関数を加えtemplateにフィルターをかけることで解決できた。もっともこれは自己解決は出来ず質問したんだけど。
models.py
〜 class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') date_limit = models.DateTimeField('公開期限', default = timezone.now() + timedelta(days=7) ) def is_date_limit(self): # まだ公開期限を過ぎていないならTrue now = timezone.now() return now <= self.date_limit 〜
detail.html
〜 {% if question.is_date_limit %} {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} <form action="{% url 'polls:vote' question.id %}" method="POST"> {{ form.non_field_errors }} {% for field in form %} <div class="form-group"> <label for="{{ field.id_for_label }}">{{ field.label_tag }}</label> {{ field }} {{ field.errors }} </div> {% endfor %} {% csrf_token %} <button type="submit" class="btn btn-dark">送信</button> </form> {% endif %} 〜
これでフィルターをかけてます。 {% if question.is_date_limit %}
いろいろな方法を考えたが素直に公開期限をmodelsに加えることで自由に期限を設定することができた。
全体的な感想
思ったより時間がかかった。だが一方で苦戦するかと思ったデプロイは簡単だった。 さくらVPSで公開。もっとも更新ってどうやるのかわかっていないのだけれど。 知識がないので設計の段階で投票とコメント投稿は分けたほうがよいのかといったところが分からず同時並行的に2つのパターンを作っていったので余計時間がかかった。 気が付いたら1月くらいは制作に費やしてしまった。 次は掲示板アプリを作ろうと思う。それと同時並行して関数などの基本の勉強をもう一度やろうと思っている。 とりあえずアンケートサイトが完成してほっとしている。 1つ形になったのはよいことだ。