質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.12%

[django]プライマリーキーの値を保持したままリンクを飛びたい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 846

sr2460

score 37

python=3.7.0
django=(2, 0, 2, 'final', 0)

の環境を使っております。

Djagoチュートリアルを見て投票アプリケーションを作成しています。
投票した後にその投票に紐つけた状態でコメントを書けるように改造を加えようとしていますが試行錯誤していてうまくいきません。
イメージ説明

上のページのurl(http://127.0.0.1:8000/polls/6/results/)を保持したままコメントをどうぞのリンクを踏めば紐つけた状態でコメントページに進めると思ったのですがエラーが出てしまいます。

イメージ説明

url.pyにpath('add/<int:pk>/', views.add, name='add'),を表記し、

from django.urls import path
from .import views

app_name = 'polls'
urlpatterns = [
    path('', views.IndexView.as_view(), name='view'),
    path('<int:pk>/', views.DetailView.as_view(), name='detail'),
    path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
    path('<int:question_id>/vote/', views.vote, name='vote'),
    path('add/<int:pk>/', views.add, name='add'),
    path('comment/', views.comment, name='comment'),
]

views.pyの関数def add(request, pk):
以下にプライマリーキーを取得できるように関数を作りました。

from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render, redirect
from django.urls import reverse
from django.views import generic
from django.utils import timezone
from .forms import CommentForm

from .models import Choice, Question, Comment


class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'latest_question_list'

    def get_queryset(self):
        """Return the last five published questions."""
        return Question.objects.order_by('-pub_date')[:5]


class DetailView(generic.DetailView):
    model = Question
    template_name = 'polls/detail.html'
    def get_queryset(self):
        return Question.objects.filter(pub_date__lte=timezone.now())


class ResultsView(generic.DetailView):
    model = Question
    template_name = 'polls/results.html'



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):
        return render(request, 'polls/detail.html', {
            'question': question,
            'error_message': "投票内容を選んでください",
        })
    else:
        selected_choice.votes += 1
        selected_choice.save()
        return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))


def get_queryset(self):
    """
    Return the last five published questions (not including those set to be
    published in the future).
    """
    return Question.objects.filter(
        pub_date__lte=timezone.now()
    ).order_by('-pub_date')[:5]

def add(request, pk):
    #urlのpkを基に、Commentを取得
    day = get_object_or_404(Comment, pk=pk)

    #フォームに取得したCommentを紐つける
    form = CommentForm(request.POST or None)

    # method = POST、つまり送信ボタン押下時、入力内容に問題なければ
    if request.method == 'POST' and form.is_valid():
        form.save()
        return redirect('polls:comment')

    #通常時のページアクセスや、入力内容に誤りがあればまたページを表示
    context = {
        'form':form
    }
    return render(request, 'polls/day_form.html', context)


def comment(request ,pk):
    context = {
      'comment_list':Comment.objects.all(),
    }
    return render(request, 'polls/comment_list.html', context)

models.pyのclass Comment(models.Model)は

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('日付', default=timezone.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)


class Comment(models.Model):
    title = models.TextField('コメント')
    question = models.ForeignKey(Question, verbose_name='紐づく質問', on_delete=models.PROTECT)

    def __str__(self):
        return self.text[:10]

forms.pyからフォームを受け取っています。

from django import forms
from .models import Comment


class CommentForm(forms.ModelForm):

    class Meta:
        model = Comment
        fields = '__all__'

templateフォルダに
basesite.htmlというファイルを設け

{% block branding %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">投票アプリケーション</a></h1>
{% endblock %}

とだけ記述してあります。

しかしresult.htmlの{% url 'polls:add' question.id %}表記が間違っているらしく最初に書いたエラーが出てしまうのです。

<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>投票ありがとうございました</a>
<a href="{% url 'polls:add' question.id %}">コメントをどうぞ</a>

idを保持したリンクを作れるようにしなくてはいけない

またindexページはこのように記述しており"{% url 'polls:detail' question.id %}"で各々の質問に飛ぶようになっております。このリンクは正常に動作しています。

{% load static %}

<link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}">

{% if latest_question_list %}
    <ul>
    {% for question in latest_question_list %}
        <li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
    {% endfor %}
    </ul>
{% else %}
    <p>質問がひとつもありません</p>
{% endif %}

投票と紐つけてコメントを書いてもらうという仕組みであれば今の方法にはこだわりません。
参考書籍などでも構いませんのでご教授いただけると幸いです。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • gh640

    2018/11/26 12:48

    「Djagoチュートリアル」というのは https://docs.djangoproject.com/ja/2.1/intro/tutorial01/ のことを指してらっしゃいますね?

    キャンセル

  • sr2460

    2018/11/26 20:42

    results.htmlのコードも記載しました。そうです。Djangoチュートリアルはそれであっています。ただこれを投票+コメントという風に改造しようとしているところで行き詰っています。このリンク先の投票する部分のように改造しようとしています。https://llabtooflatot.blog.fc2.com/blog-entry-9821.html

    キャンセル

  • gh640

    2018/11/26 22:32

    追記・ご返信いただきありがとうございます。回答させていただいたのでまたご都合のよいときにご確認ください :D

    キャンセル

回答 1

checkベストアンサー

+1

テンプレートのコードをお載せいただきありがとうございます。

該当する部分だけ { と } が全角になっているためではないかと思います。パッと見せていただくかぎり対象 URL が読み込めない理由は urlconf や view には無さそうですので、これら(= { と } )を半角に変更してお試しになってみてください :)

<a>投票ありがとうございました</a>
- <a href="{% url 'polls:add' question.id %}">コメントをどうぞ</a>
+ <a href="{% url 'polls:add' question.id %}">コメントをどうぞ</a>

(この全角と半角の問題、目視で見てもわからなかったりするので、ハマりますよね)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/27 10:16

    ありがとうございます!!リンクが飛びました!!!またここからいろいろ作ってみます!!
    ほんとうにありがとうございました!

    キャンセル

  • 2018/11/27 15:40

    よかったです!がんばってください :D

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.12%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる