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

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

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

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

Python 3.x

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

Python

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

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

1回答

1396閲覧

<python,django>投稿されたコメントにカウンターボタン(いいねボタン)を設置したい

sr2460

総合スコア50

Django

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

Python 3.x

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

Python

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

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

0クリップ

投稿2019/01/26 04:46

編集2019/01/26 05:32

前提・実現したいこと

ボタンを押すと数値が増えるカウンターボタンを投稿されたコメントに紐づけたいです。
投稿ページを別に作ってそこに遷移させればもっと簡単だとは思うのですが、今回は1つのページ内で行いたいと思っています。

該当のソースコード

ここに投稿フォームの表示。投稿されたコメントの表示。いいねボタンの設置の3つを1ページで実現しようとしています。
board.html

html

1#ここがコメントの投稿フォームです 2<form action="" method="POST" enctype="multipart/form-data"> 3{{ form.as_p }} 4<button type="submit">送信</button> 5{% csrf_token %} 6</form> 7 8#ここがコメントの表示部分です 9{% for post in post_list %} 10 11<p>{{ post.name }}</p> 12<p>{{ post.text | linebreaksbr }}</p> 13{% if post.file %} 14<p><img src="{{ post.file.url }}" ></p> 15{% endif %} 16 17<p>{{ post.date }}</p> 18 19#ここにいいねボタンを設置。postのidと紐つけていいねボタンを押すとカウントが増えていく 20<h3>"いいね"ボタンを押してください</h3> 21<form action="{% url 'board:good' question.id %}" method="post"> 22 {% csrf_token %} 23 <input type="submit" name="good" value="いいね">({{ good_count }} いいね) 24</form> 25 26 27 28{% endfor %} 29

関数でgoodを機能させるURLであるgood/int:pkを設置しています。
urls.py

python

1 2 3 #!/usr/bin/env python 4# -*- coding: utf-8 -*- 5 6from django.urls import path 7 8from . import views 9 10app_name = 'board' 11urlpatterns = [ 12 path('', views.FormAndListView.as_view(), name='board'), 13 path('good/<int:pk>/', views.good, name='good'), 14] 15 16 17 18

class Goodはclass Postに紐つけています。

models.py

from django.db import models from django.utils import timezone class Post(models.Model): class Meta: verbose_name = '投稿' verbose_name_plural = '投稿リスト' name = models.CharField('名前', max_length=20) text = models.TextField('本文') date = models.DateTimeField('日付', default=timezone.now) file = models.FileField('ファイル', blank=True, null=True) def __str__(self): return self.text class Good(models.Model): """いいね.""" created_at = models.DateTimeField(default=timezone.now) good = models.ForeignKey(Post, on_delete=models.CASCADE, null=True) class Meta: db_table = 'good' verbose_name = verbose_name_plural = 'いいね'

フォームと投稿されたコメントといいねボタンの表示。

class FormAndListView(FormView, ListView, TemplateResponseMixin): def get(self, request, *args, **kwargs): formset = PostForm(request.POST or None, files=request.FILES or None) formView = FormView.get(self, request, *args, **kwargs) listView = ListView.get(self, request, *args, **kwargs) formData = formView.context_data['form'] listData = listView.context_data['object_list'] good_count = Good.objects.count() context = {'form' : formData, 'post_list' : listData, 'good_count' : good_count} return render(request, 'board/board.html', context)

いいねボタンをクリックすると数値が増える。

def good(request, pk): """いいねボタンをクリック.""" pk = get_object_or_404(Post, pk=pk) if request.method == 'POST': # データの新規追加 Good.objects.create(pk=request.POST['good']) context = {'pk' : pk} return redirect('board:board')

###エラーメッセージ

django.urls.exceptions.NoReverseMatch: Reverse for 'good' with arguments '('',)' not found. 1 pattern(s) tried: ['board/good/(?P<pk>[0-9]+)/$']

pk関連のコードを削除した場合いいねボタンで数値が増加することは確認しております。ただしその場合コメントへの紐づけが行われません。

試したこと

現在はurlからプライマリーキーを紐つけるコードの書き方なのでこのままでは実現が難しいことは理解しているのですが・・・。
urlに情報が無い状態でPostのプライマリーキーを特定して紐つけることがdjangoで果たしてかのうなのでしょうか。

補足情報(FW/ツールのバージョンなど)

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

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

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

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

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

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

guest

回答1

0

ベストアンサー

ご認識の課題がいくつかあるようですので、できる範囲でひとつひとつお答えさせていただきますね。

  1. エラー

text

1django.urls.exceptions.NoReverseMatch: Reverse for 'good' with arguments '('',)'

このエラーは、変数 question が存在しないために {% url 'board:good' question.id %} の行で発生しているようです。最後の引数は question.id ではなく post.id ではないでしょうか。

  1. goodpost へのひもづけ

1 のポイントを直すと、いいねフォームの送信時に関数 good()post.pk (= pk )が渡されるはずなので、それで解決となるのではないかと思います。ただし good() は例えば次のようにした方がよい気がします(細かな説明は割愛しますが、コードをご覧いただくと自明かと思いますので、読み取ってください)。

patch

1def good(request, pk): 2 """いいねボタンをクリック.""" 3- pk = get_object_or_404(Post, pk=pk) 4+ post = get_object_or_404(Post, pk=pk) 5 if request.method == 'POST': 6 # データの新規追加 7- Good.objects.create(pk=request.POST['good']) 8+ Good.objects.create(good=post) 9- context = {'pk' : pk} 10 return redirect('board:board')

(蛇足ですが、個人的には Good から Post を参照する ForeignKeygood という名前をつけるといろいろと混乱しそうなので、素直に post 等の名前に方がよいかな、という気がします)

  1. その他

余談です。 DateTimeFielddefault=timezone.now とするのはあまりよくないので、代わりに auto_now を使う方がよいかと思います。

patch

1- created_at = models.DateTimeField(default=timezone.now) 2+ created_at = models.DateTimeField(auto_now=True)

理由は次のページ等でわかりやすく説明されているのでそちらをご覧になってみてください。

  1. URL 以外での外部キーひもづけ

urlに情報が無い状態でPostのプライマリーキーを特定して紐つけることがdjangoで果たしてかのうなのでしょうか。

可能かと思います。一般的な方法は、対象のプライマリーキーを格納した hidden フィールドをフォームに追加しておいてそれを取得する、というやり方でしょうか。

ご参考になれば幸いです。

投稿2019/01/26 06:06

編集2019/01/26 13:14
gh640

総合スコア1407

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

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

sr2460

2019/01/26 07:24 編集

いつもありがとうございます!! エラーについてですが見落としでした。これは気がつけるミスですし気を付けていきたいなと思います。 patch部分についても基本的な部分は何とか僕でも読めていると思います。 確かにこれで投稿にいいねが紐つけられましたしそれは管理画面でも確認できました。 auto_now=Trueの部分については英語サイトなこともあり苦戦していますが、理解できるように努めます。 現在これによりエラーは出ておりません。本当にありがとうございました。 現在まだhtmlですべてのいいねの総数がそのままカウントされているので、現在そこを検討しています。 アドバイスしていただいた 対象のプライマリーキーを格納した hidden フィールドをフォームに追加しておいてそれを取得する good_count = Good.objects.count() の段階でなにかフィルターをかけてhtmlに表示される際はコメントにつけられたいいねの数ごとに表示ができないか? html部分の{{ good_count }}のところを改造してプライマリキーごとに表示できないか? などを検討して調べております。 リストでテンプレートに渡しているので {% for x, y in data.items %}のような形でhtmlを書いて、そのうえでプライマリーキーをhtmlの方に渡せればできるような気はしているのですが。 すぐにベストアンサーを付けたいのですがいましばらく待っていただけると幸いです。
gh640

2019/01/26 13:25

そうですか。前進されたようでよかったです :D > 現在まだhtmlですべてのいいねの総数がそのままカウントされているので、現在そこを検討しています。 > html部分の{{ good_count }}のところを改造してプライマリキーごとに表示できないか? `post` ごとにいいねの数をカウントされたい感じですかね。こうなる理由はご自身でお調べになってみていただければと思いますが、 `{{ good_count }}` を `{{ post.good_set.count }}` と書き換えると、 `post` ごとのいいねの数が表示できるのではないかと思います。お試しになってみてください。
sr2460

2019/01/27 09:55 編集

ありがとうございます!!! class postにForeignkeyで紐づいたgoodをあらわすときに_setを使うという部分で似たようなことを確か以前にも教えて頂いた記憶があります。 また仮に_set.allですと一般的にすべてが表示されるような表現ですが、後ろに.countがつくとpostに紐づいたgoodを数えられるのでしょうね。 一度教えていただいたことですからできれば自分から応用できると一番良いのですが、大変お手数をおかけいたします。 また自分でも頂いたアドバイスを元に試行錯誤しまして class Post(models.Model): class Meta: verbose_name = '投稿' verbose_name_plural = '投稿リスト' name = models.CharField('名前', max_length=20) text = models.TextField('本文') date = models.DateTimeField('日付', default=timezone.now) file = models.FileField('ファイル', blank=True, null=True) good = models.IntegerField(default=0) def __str__(self): return self.text def good(request, pk): """いいねボタンをクリック.""" post = get_object_or_404(Post, pk=pk) if request.method == 'POST': # データの新規追加 post.good += 1 post.save() return redirect('board:board') <form action="{% url 'board:good' post.id %}" method="post"> {% csrf_token %} <input type="submit" name="good" value="いいね">({{ post.good }} いいね) </form> という方法でも同様のことが実現できることが分かりました。 現在2つの方法があるので今後実現したいことに合わせて(いいねボタンを押した時に画面遷移をせずにカウントを増やす。他のページとのリンクの兼ね合いなど)どちらの方法が良いか検討していきます。 本当にありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問