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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

HttpWebRequest

HttpWebRequestとは.NETにおけるクラスであり、WebRequestクラスをHTTPに導入するものです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

1708閲覧

(python,django)ラジオボタンにフィルターをかけて表示をしたい

sr2460

総合スコア50

Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

HttpWebRequest

HttpWebRequestとは.NETにおけるクラスであり、WebRequestクラスをHTTPに導入するものです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2018/12/17 04:56

編集2018/12/17 06:03

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

の環境で開発しています。
Djangoチュートリアルで学んだ投票アプリに改造を加えコメント投稿機能を追加しております。
Djangoチュートリアル。
https://docs.djangoproject.com/ja/2.1/intro/tutorial01/

前提・実現したいこと

質問ごとに選択肢を設けコメントともに(空欄可能)投票させるアプリを作成していますが、選択肢にフィルターをかけられずに悩んでおります。
イメージ説明
イメージ説明

ベルマーレMVPへの質問の選択肢は2つ目の画像の選択しだけなのだが実際には他の質問への選択肢や------
という選択肢が表出されてしまう。

前提条件としてコードは

models.py

python

1class Choice(models.Model): 2 question = models.ForeignKey(Question, on_delete=models.CASCADE) 3 choice_text = models.CharField(max_length=200) 4 votes = models.IntegerField(default=0) 5 6 def __str__(self): 7 return self.choice_text 8 9 10class Choice_Comment(models.Model): 11 choice = models.ForeignKey(Choice, on_delete=models.CASCADE) 12 choice_comment_text = models.TextField('コメント', blank=True, null=True) 13

forms.py

python

1class ChoiceCommentForm(forms.ModelForm): 2 choice =forms.ModelChoiceField( 3 queryset=Choice.objects.all(), 4 widget=forms.RadioSelect, 5 ) 6 7 class Meta: 8 model = Choice_Comment 9 fields ="__all__"

views.py

python

1 2class DetailView(ModelFormMixin, generic.DetailView): 3 model = Question 4 template_name = 'polls/detail.html' 5 form_class = ChoiceCommentForm 6 def get_queryset(self): 7 return Question.objects.filter(pub_date__lte=timezone.now()) 8 9 10def vote(request, question_id): 11 question = get_object_or_404(Question, pk=question_id) 12 form = ChoiceCommentForm(request.POST or None) 13 try: 14 selected_choice= question.choice_set.get(pk=request.POST['choice']) 15 except (KeyError, Choice.DoesNotExist): 16 return render(request, 'polls/detail.html', { 17 'question': question, 18 'error_message': "投票内容を選んでください", 19 }) 20 else: 21 selected_choice.votes += 1 22 selected_choice.save() 23 form.save() 24 context ={ 25 'comment_ichiran':selected_choice, 26 } 27 return HttpResponseRedirect(reverse('polls:results', args=(question.id,)), context)

urls.py

python

1from django.urls import path 2 3from . import views 4 5app_name = 'polls' 6urlpatterns = [ 7 path('', views.IndexView.as_view(), name='index'), 8 path('<int:pk>/', views.DetailView.as_view(), name='detail'), 9 path('<int:pk>/results/', views.ResultsView.as_view(), name='results'), 10 path('<int:question_id>/vote/', views.vote, name='vote'), 11 path('<int:post_pk>/comment/', views.CommentView.as_view(), name='comment'), 12 path('<int:pk>/comment_list/', views.commentlist, name='comment_list'), 13] 14

detail.html

html

1<h1>{{ question.question_text }}</h1> 2 3{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} 4 5<form action="{% url 'polls:vote' question.id %}" method="post"> 6{% csrf_token %} 7 8{{ form.as_p }} 9 10<input type="submit" value="投票"> 11 12</form> 13

forms.pyの

queryset=Choice.objects.all(),

filterをうまくかければその質問に対する質問だけを表示できると思いいろいろ試してました。

試したこと

forms.py

python

1class ChoiceCommentForm(forms.ModelForm): 2 choice_text = Choice.objects.all() 3 choice =forms.ModelChoiceField( 4 #queryset=Choice.objects.all(), 5 queryset = Choice.objects.filter(choice_text=choice_text).all().order_by('pk'), 6 widget=forms.RadioSelect, 7 ) 8 9 class Meta: 10 model = Choice_Comment 11 fields ="__all__" 12

エラーメッセージ

error

1Error during template rendering 2In template C:\Users\Desktop\mysite\polls\templates\polls\detail.html, error at line 13 3 4The QuerySet value for an exact lookup must be limited to one result using slicing. 53 {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} 64 75 <form action="{% url 'polls:vote' question.id %}" method="post"> 86 {% csrf_token %} 97 {% for choice in question.choice_set.all %} 108 <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}"> 119 <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br> 1210 {% endfor %} 1311 1412 1513 {{ form.as_p }} 1614 1715 <input type="submit" value="投票"> 1816 1917 </form> 2018

試したこと2

forms.py
コード

python

1class ChoiceCommentForm(forms.ModelForm): 2 choice_text = get_object_or_404(Question, pk=question_id) 3 choice =forms.ModelChoiceField( 4 #queryset=Choice.objects.all(), 5 queryset = Choice.objects.filter(choice_text=choice_text), 6 widget=forms.RadioSelect, 7 ) 8 9 class Meta: 10 model = Choice_Comment 11 fields ="__all__" 12

エラーメッセージ

error

1 class ChoiceCommentForm(forms.ModelForm): 2 File "C:\Users\Desktop\mysite\polls\forms.py", line 20, in ChoiceC 3ommentForm 4 choice_text = get_object_or_404(Question, pk=question_id) 5NameError: name 'question_id' is not defined

試したこと3

forms.py

python

1class ChoiceCommentForm(forms.ModelForm): 2 #choice_text = models.ForeignKey(Question, on_delete=models.CASCADE) 3 choice =forms.ModelChoiceField( 4 #queryset=Choice.objects.all(), 5 queryset = Choice.objects.filter(pk=1), 6 widget=forms.RadioSelect, 7 ) 8 9 class Meta: 10 model = Choice_Comment 11 fields ="__all__" 12

エラーメッセージは出ずにpk=1の選択肢だけが出てきました。
イメージ説明

試したこと4

forms.py

python

1class ChoiceCommentForm(forms.ModelForm): 2 choice_text = models.ForeignKey(Question, on_delete=models.CASCADE) 3 choice =forms.ModelChoiceField( 4 #queryset=Choice.objects.all(), 5 queryset = Choice.objects.filter(choice_text=choice_text), 6 widget=forms.RadioSelect, 7 ) 8 9 class Meta: 10 model = Choice_Comment 11 fields ="__all__"

error

1 "Choices are: %s" % (name, ", ".join(available))) 2django.core.exceptions.FieldError: Cannot resolve keyword 'choice_text' into fie 3ld. Choices are: choice, comment, id, pub_date, question_text

quesrysetの手法を理解しきれてないいないためドキュメントで勉強中です。
https://docs.djangoproject.com/ja/2.1/topics/db/queries/

おそらく

urls.py

1path('<int:pk>/', views.DetailView.as_view(), name='detail'),

のpkを読み取れれば解決すると思うのですが・・・。
アドバイスをお願いいたします。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yamato_user

2018/12/17 06:11

Choiceモデルの中身を示してください
sr2460

2018/12/18 01:34 編集

お返事ありがとうございます!!!! これでよろしいでしょうか? models.py 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
guest

回答1

0

ベストアンサー

「 URL のパラメータ pkChoiceCommentForm に渡して、 choice の選択肢を絞り込みたい」ということだと理解しましたがこの理解で合っていますか?

もしこの理解が正しければ、 ChoiceCommentForm のインスタンス生成時に view から ChoiceCommentFormquestion を渡してあげればよいのではないかと思います。

例えば次のようにするとよいでしょうか。

ChoiceCommentForm:

python

1class ChoiceCommentForm(forms.ModelForm): 2 choice =forms.ModelChoiceField( 3 widget=forms.RadioSelect, 4 ) 5 6 # (省略) 7 8 def __init__(self, *args, **kwargs): 9 question = kwargs.pop('question', None) 10 super().__init__(*args, **kwargs) 11 12 # choice の選択肢を question に関係したものに絞り込む 13 if qustion_pk: 14 self.fields['choice'].queryset = Choice.objects.filter(question=question),

vote() の方ではこの __init__() を活用するようにします。

vote():

python

1def vote(request, question_id): 2 question = get_object_or_404(Question, pk=question_id) 3 # choice の選択肢を question に関係したものに絞り込む 4 form = ChoiceCommentForm(request.POST or None, question=question) 5 # (省略)

動作確認してませんので、細かなところで間違っている可能性があるものと思います。ですので、コピペされるのではなく、大まかな方向性・アイデアの部分だけ読み取っていただければと思います :)

ちなみに、 ModelForm のサブクラスで __init__() を定義する場合は、少なくとも ModelForm__init__() がどのようになっているのかは知っておくべきだと思います。できれば ModelForm の親クラスも含めてフォームクラスの処理全体を知っておくべきですが、そのあたりはご自身の現状のスキルや時間が許す範囲で調べられるとよいのではないでしょうか。

Modelform.__init__():

おそらく同様のニーズに対する Q&A が Stack Overflow にありました。こちらもご参考になるものと思います。

追記 1:

コメントとお試しいただきありがとうございます。すみません、いくつか間違いがありましたね。お手伝いするつもりが余計なお手間をかけてしまいました。。

例えば、

python

1 def __init__(self, *args, **kwargs): 2 question = kwargs.pop('question', None) 3 print(question) 4 super().__init__(*args, **kwargs) 5 6 # choice の選択肢を question に関係したものに絞り込む 7 if question: 8 print('here') 9 self.fields['choice'].queryset = Choice.objects.filter(question=question),

とすると、 question__init__() に正しく渡されているのかを print() の出力によって確認できると思うので、よろしければお試しになってみてください。

追記 2:

すみません、変更すべき view は DetailView だったのですね。。。

次のようにされるとよいものと思います。

URL パラメータを DetailView.dispatch() で取得して、それを get_form_kwargs() を使って ChoiceCommentForm に渡します。 ChoiceCommentForm の方では __init__() でそれを受け取って choice フィールドの queryset の絞り込みに使います。

おおよそ次のとおりに書くことで絞り込みがうまくできることを私の環境で確認していますが、細かいところは私がミスしている可能性がありますのであくまでも参考に(まるっぽコピペではなく)お試しになってみてください。

views.py:

python

1class DetailView(ModelFormMixin, generic.DetailView): 2 model = Question 3 template_name = 'polls/detail.html' 4 form_class = ChoiceCommentForm 5 6 def get_queryset(self): 7 return Question.objects.filter(pub_date__lte=timezone.now()) 8 9 def dispatch(self, request, *args, **kwargs): 10 self.target_question = get_object_or_404(Question, pk=kwargs['pk']) 11 return super().dispatch(request, *args, **kwargs) 12 13 def get_form_kwargs(self): 14 kwargs = super().get_form_kwargs() 15 kwargs['target_question'] = self.target_question 16 return kwargs

forms.py:

python

1class ChoiceCommentForm(forms.ModelForm): 2 choice = forms.ModelChoiceField( 3 queryset=Choice.objects.all(), widget=forms.RadioSelect 4 ) 5 6 class Meta: 7 model = Choice_Comment 8 fields = "__all__" 9 10 def __init__(self, *args, **kwargs): 11 question = kwargs.pop('target_question', None) 12 super().__init__(*args, **kwargs) 13 14 # choice の選択肢を question に関係したものに絞り込む 15 if question: 16 self.fields['choice'].queryset = Choice.objects.filter(question=question)

お手伝いするつもりがかえって遠回りをさせる形になってしまいました。ご容赦ください >_<

投稿2018/12/17 06:15

編集2018/12/19 04:59
gh640

総合スコア1407

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sr2460

2018/12/18 03:52

お返事ありがとうございます。 はい「 URL のパラメータ pk を ChoiceCommentForm に渡して、 choice の選択肢を絞り込みたい」という認識であっております! とりあえずコードをそのまま写したところ File "C:\Users\Desktop\mysite\polls\forms.py", line 23, in ChoiceC ommentForm widget=forms.RadioSelect, TypeError: __init__() missing 1 required positional argument: 'queryset' とエラーが出たため一旦 queryset=Choice.objects.all(), を復帰させ再度試してみました。 すると今度は name 'question_pk' is not defined エラーが発生いたしました。ですので if question_pk: を if question: に変更するとエラーは出ませんでしたがフィルターはかかりませんでした。 フォームをラジオボタンにするコードは最終的には欲しいですが一旦消去し、 choice =forms.ModelChoiceField( widget=forms.RadioSelect, ) を消去した状況でフィルターをかけられるかいろいろ実験している状態です。
gh640

2018/12/18 04:57

コメントお戻しくださりありがとうございます。 コードに基本的なミスがいくつかあり余計なお手間をおかけしてしまい申し訳ありません。。いただいたコメントを受けて回答欄に追記させていただきましたのでご覧ください :) ( `__init__()` の中の `if question` の中を通っているのかどうかを確認されると、フィルタがなぜかからないのかの原因の特定に一歩近づくのではないかと思います)
sr2460

2018/12/18 06:58 編集

素早いお返事ありがとうございます。 教えていただいたコードを使わせていただいたところ特に先ほどとは表示が変わりませんでした。printの部分も特に表示されていませんでした。 ただしフォームを送信するとエラー 'tuple' object has no attribute 'model' が出現したのでvote方を少しいじりまして def vote(request, question_id): question = get_object_or_404(Question, pk=question_id) # choice の選択肢を question に関係したものに絞り込む form = ChoiceCommentForm(request.POST or None)#, question=question)←ここをいったんコメントアウト としたところフォームはきちんと送信されました。 ただquestion=questionの部分は無いと結局フィルターはかからないと思いますが。 ただなんとなく form = ChoiceCommentForm(request.POST or None, question=question)にしてしまうとフォームも送信できないところがフィルターがかからないこととも関連しているのかなと漠然と考えております。 現在もコードを改造してみたり、本やネット上の記事を見ながらなにか方法はないか試しているような状況です。 なお #choice =forms.ModelChoiceField( #widget=forms.RadioSelect, #) の部分はあるとエラーが出てしまうので現在はコメントアウトしております。
gh640

2018/12/18 07:11 編集

なるほど、ありがとうございます。度々すみません・・・ 'tuple' object has no attribute 'model' のエラーの原因は私が書いたコードの末尾の `,` ですね。。 `,` を取って、つまり、次のように変更して改めて実行してみてください。 ```patch - self.fields['choice'].queryset = Choice.objects.filter(question=question), + self.fields['choice'].queryset = Choice.objects.filter(question=question) ``` tuple なんちゃらというエラーが出るということは、少なくとも POST のときにはこの一行(≒ if 文の中)が実行されているということで、前進はしている気がします。 ただ、私の理解が正しければ `print(question)` は必ず実行されるはずだと思うのですが、何も出力しないのはなぜなのでしょうね。 `print(question)` だと `question` が `None` のときに出力がされているのかされていないのかよくわからないので、例えば `print('question: {}'.format(question))` とご変更いただくと状況がわかりやすくなるかもしれません。
sr2460

2018/12/19 03:42

お世話になっております。いつもお返事ありがとうございます! まずpatchを入れましたところエラーが解決されフォームが送信されました。 本当にありがとうございます! またprint(question)→print('question: {}'.format(question))に変更しましたがこちらは変化がありませんでした。 formに関してclass DetailView(ModelFormMixin, generic.DetailView): で出現させているのでCreateViewで出現させた場合print部分が出現するかどうか試しております。 (まだプライマリーキーの部分が読み取れずエラーが出てしまいますが・・・。) また隠すものでもありませんので現在までのコードを一旦gitghubにアップロードしました。 https://github.com/sr2460/test 自分でもできる限り調査して実験を続けております。
gh640

2018/12/19 04:51

なるほど、謎のわけがわかりました。対象のページは `vote()` ではなく `DetailView` が担っているのですね。それは `vote()` を書き換えても何も起こらないわけですよね。。。申し訳ありません、何度も `DetailView` に言及されているのに根本的なところで勘違いしていました。。。 すみません、ここまでの `vote()` のやりとりは忘れてください >_<
sr2460

2018/12/19 04:59

いえ。こちらこそ申し訳ありません。 恥ずかしながら私もDjangoチュートリアルの解説を読んでもdef voteとclass DetailViewの部分の関わり合いをいまひとつ理解しておりませんでしたのでこのようなことが起こったと思っております。 本当に感謝しております!
gh640

2018/12/19 05:01

追記 2 を書かせていただきました。ご覧になってみてください :) また、細部は違いますが、( URL のパラメータをフォームに渡したい、という意味で)同様の質問をされている方がいらっしゃいました。その回答もご参考になると思いますので、よろしければご覧になってみてください: https://teratail.com/questions/164646
sr2460

2018/12/19 08:25

ありがとうございました!!!思っていたような仕様で実装できました!! まだコードの細かい部分の意味が理解できていないのですが、頂いたリンクなどを基に勉強してまいりたいと思います。 あと一歩で完成になると思います。本当にありがとうございます!!
gh640

2018/12/19 09:26

そうですか!それはよかったです! ご丁寧にありがとうございます。がんばってください :D
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問