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

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

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

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

Python 3.x

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

Q&A

解決済

1回答

5250閲覧

Djangoで掲示板を作りたい

champuyo

総合スコア15

Django

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

Python 3.x

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

0グッド

0クリップ

投稿2019/05/28 08:12

編集2019/05/29 07:41

###初めにご挨拶

プログラミング初心者です
現在独学でプログラミングを勉強しています
情報源はネットのみです

質問が下手くそなので先に謝りたいと思います
申し訳ありません

前提・実現したいこと

現在Djangoで掲示板を作ろうとしています

スレッドをクリック

選択したスレッドの投稿一覧を表示
ということをしたいです

【スレッド一覧画面↓】
スレッド一覧画面
【ユーザーの投稿一覧↓】
ユーザーの投稿一覧

発生している問題・エラーメッセージ

ですが現在はどのスレッドをクリックしても
全ての投稿が表示されます

仕組みとして
スレッドはサイト運営者がadminサイトで作成・削除を行い
投稿はユーザーがウェブブラウザ上から投稿します

希望する条件としては
投稿画面はListView(もしくはDetailView)とCreateViewを組み合わせて
一つの画面で表示したいです

そもそも根本的なこと変えたほうがいいだとか
こういうやり方の方が後々ラクだとかがあれば
それも教えて頂きたいです

丸投げな質問過ぎますかね…

該当のソースコード

ディレクトリ構造は、以下です。

├── bbs │ ├── __init__.py │ ├── templates(以下省略) │ ├── __pycache__(以下省略) │ ├── admin.py │ ├── apps.py │ ├── migrations(以下省略) │ ├── models.py │ ├── urls.py │ ├── forms.py │ ├── tests.py │ └── views.py ├── db.sqlite3 ├── manage.py ├──myvenv(以下省略) └── pj ├── __init__.py ├── __pycache__(以下省略) ├── settings.py ├── urls.py └── wsgi.py

urls.py(bbsディレクトリ)

python

1from django.urls import path 2from .views import ThreadListView,PostCreateAndListView 3 4app_name = 'bbs' 5urlpatterns = [ 6 path('thread/', ThreadListView.as_view(), name='thread'), 7 path('thread/<int:pk>/', PostCreateAndListView.as_view(), name='post'), 8]

views.py

python

1from django.shortcuts import render 2from django.urls import reverse_lazy 3from django.views.generic.edit import CreateView 4from django.views.generic import ListView, DetailView 5from .models import Thread,Post 6from .forms import ThreadForm, PostForm 7 8class ThreadListView(ListView): 9 model = Thread 10 template_name = "bbs/thread.html" 11 12class PostCreateView(CreateView): 13 form_class = PostForm 14 template_name = "bbs/post.html" 15 success_url = reverse_lazy('bbs:post') 16 17class PostListView(ListView): 18 model = Post 19 20class PostCreateAndListView(PostCreateView,PostListView): 21 def get(self, request, *args, **kwargs): 22 formView = PostCreateView.get(self, request, *args, **kwargs) 23 listView = PostListView.get(self, request, *args, **kwargs) 24 formData = formView.context_data['form'] 25 listData = listView.context_data['object_list'] 26 context = {'form' : formData, 'post_list' : listData} 27 return render(request, 'bbs/post.html', context)

forms.py

python

1from django import forms 2from .models import Thread,Post 3 4 5class ThreadForm(forms.ModelForm): 6 class Meta: 7 model = Thread 8 fields = ("subject",) 9 10class PostForm(forms.ModelForm): 11 class Meta: 12 model = Post 13 fields = ("message",)

models.py

python

1from django.db import models 2from django.utils import timezone 3from account.models import User 4 5 6class Thread(models.Model): 7 subject = models.CharField(max_length=255) 8 9 def __str__(self): 10 return self.subject 11 12class Post(models.Model): 13 thread = models.ForeignKey(Thread, on_delete=models.CASCADE, null=True, related_name='threads') 14 message = models.TextField(max_length=3000) 15 created_at = models.DateTimeField(auto_now_add=True) 16 created_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='post', null=True) 17 def __str__(self): 18 return self.message

thread.html

python

1{% extends 'home/base.html' %} 2 3{% block content %} 4 <div class="contents"> 5<ul> 6 {% for item in object_list %} 7 <li><a href="{% url 'bbs:post' pk=item.pk %}">{{ item }}</a></li> 8 {% endfor %} 9</ul> 10 </div> 11 12 13{% endblock %}

post.html

python

1<!DOCTYPE html> 2<html lang="ja"> 3<head> 4 <meta charset="UTF-8"> 5 <title>タイトル</title> 6</head> 7<body> 8 <h1>掲示板だよ</h1> 9 <ul> 10 {% for post in post_list %} 11 <li>本文:{{ post.message }}</li> 12 <li>投稿日時:{{ post.created_at }}</li> 13 <li>投稿者:{{ post.created_by }}</li> 14 {% endfor %} 15 </ul> 16 <p>とうこうするよ</p> 17 <form action="" method = "POST"> 18 {% csrf_token %} 19 {{ form.as_p }} 20 <input type="submit"> 21 </form> 22</body> 23</html>

試したこと

ネットでひたすら調べるも一ヶ月以上経ってしまった

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

Python 3.7.3
Django 2.1.7
pytz 2018.9
OSバージョン Windows8.1
サーバー ローカルサーバ

利用している環境などの情報も
どんなことを書けばいいのかすら分かりません

必要な情報があれば教えて頂ければ随時追加したいと思います

###頂いた回答を元に作成し直しました。
希望通りの動きをしています。

urls.py

python

1from django.urls import path 2from .views import ThreadListView,post_list 3 4app_name = 'bbs' 5urlpatterns = [ 6 path('thread/', ThreadListView.as_view(), name='thread'), 7 path('thread/<int:pk>/', post_list, name='post'), 8]

views.py

python

1from django.shortcuts import redirect, render, get_object_or_404 2from django.urls import reverse_lazy 3#from django.views.generic.edit import CreateView 4from django.views.generic import ListView #DetailView TemplateView 5from .models import Thread,Post 6from .forms import ThreadForm, PostForm 7 8class ThreadListView(ListView): 9 model = Thread # Thread.objects.all()を裏側でやってくれてる 10 template_name = "bbs/thread.html" 11 12def post_list(request, pk): 13 per_page = 10 14 15 thread = get_object_or_404(Thread,pk=pk) 16 post_list= Post.objects.filter(thread=thread) 17 form = PostForm(request.POST or None) 18 19 if form.is_valid(): 20 post = form.save(commit=False) 21 post.thread = thread 22 post.save() 23 return redirect('bbs:post', pk=thread.pk) 24 25 context = {'form': form, 'post_list': post_list} 26 return render(request, 'bbs/post.html', context)

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

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

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

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

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

gh640

2019/05/28 09:01

質問文の「ディレクトリ構造」の中のおそらく `__init__.py` のところが `init.py` に変わってしまっています。コードブロックで囲われた方がきれいに表示できると思います。
champuyo

2019/05/28 10:01

全然気が付きませんでした! ありがとうございます 修正いたしました
guest

回答1

0

ベストアンサー

ですが現在はどのスレッドをクリックしても
全ての投稿が表示されます

投稿の絞り込み処理を書かれていないからではないでしょうか。

おそらく、 URL パラメータの pk を使って listData を絞り込む必要があるものと思います。 PostCreateAndListView のどこかに次のような処理を入れる必要があるはずです。

python

1thread = Thread.objects.get(pk=pk) 2listData = Post.objects.filter(thread=thread)

投稿画面はListView(もしくはDetailView)とCreateViewを組み合わせて
一つの画面で表示したいです

Django の view は class-based view と function-based view の 2 つのアプローチで作ることができますが、あくまでも class-based view で実装されたいのであれば、まず ListViewCreateView の画面を別々に完成させて、それからそれらを組み合わせた画面を作る、とステップを刻んで実装されるのがよいと思います。別々に実装してから組み合わせるのは一見遠回りに見えますが、今回は学びながら実装されているので、そちらの方が結果的に速くなる可能性が高いと思います。

もし class-based view にはこだわっていなくて function-based view でも全然問題無い、ということであれば、今の class-based view のアプローチをやめて function-based view でチャレンジされることをおすすめします。今回のような画面を作るときには function-based view を使った方がシンプル・かんたんに書けることが多いです。

お求めの答えにはなっていないかもしれません。もし「代わりにコードを書いてほしい」というご要望をお持ちであれば、他の方からの回答を待ってみてください。ご参考になれば幸いです。

追記 1

まだまだ時間がかかりそうですが、まずは頂いた回答を元に、関数ベースで投稿画面と一覧表示画面を分けたviewを作ろうと思っています。

以下、 function-based view での書き方のイメージです。ご参考になさってください。

あくまでイメージですが、投稿一覧ページは次のような感じで書くことになるでしょうか。

python

1from django.core.paginator import Paginator 2from django.shortcuts import get_object_or_404, render 3 4from .models import Thread, Post 5 6 7def post_list(request, pk): 8 """特定のスレッドの投稿を一覧表示する 9 10 引数の `pk` はスレッドの `pk` を指すので要注意 11 """ 12 per_page = 20 13 14 thread = get_object_or_404(Thread, pk=pk) 15 post_list = Post.objects.filter(thread=thread) 16 17 # ページめくり機能をサポートする 18 # (ページめくり機能が不要な場合はこの 3 行は削除してください) 19 paginator = Paginator(post_list, per_page) 20 page = request.GET.get('page') 21 post_list = paginator.get_page(page) 22 23 context = {'post_list': post_list} 24 return render(request, 'bbs/post.html', context)

一方の投稿作成ページは次のような感じになるかと思います。

python

1from django.shortcuts import get_object_or_404, redirect, render 2 3from .models import Thread 4from .forms import PostForm 5 6 7def post_create(request, pk): 8 """特定のスレッドにひもづいた投稿を作成する 9 10 引数の `pk` はスレッドの `pk` を指すので要注意 11 """ 12 thread = get_object_or_404(Thread, pk=pk) 13 form = PostForm(request.POST or None) 14 15 # フォームが送信されて、なおかつその値が正しい場合は投稿データを登録してリダイレクト 16 if form.is_valid(): 17 post = form.save(commit=False) 18 post.thread = thread 19 post.save() 20 return redirect('bbs:post', pk=thread.pk) 21 22 context = {'form': form} 23 return render(request, 'bbs/post.html', context)

post_list() の中にあるページめくり機能の部分については不要であれば削除してください(数行そのまま削除するだけでよいはず、です)。ページめくり機能を使われたい場合は、公式ドキュメントの次の箇所を参照された上でご利用になるとよろしいかと思います。

これらの view が個別にうまく動くことが確認できたら、続いてこれらのロジックを統合してひとつにすれば PostCreateAndListView 相当の view が完成するものと思います。

統合するときの考え方としては、 post_create() の方をベースに「 post_list() にあって post_create() に無いコンテキスト変数」をそこに追加していく、という方向で考えられるとおそらくスムーズです。

(このコード ↑ はあくまでアイデアをお伝えするためのものなので、私の手元で動作確認したわけではありません。細かいところが間違っている可能性もありますので、コピペでそのまま利用するのではなくアイデアの参考としてお読みください)

投稿2019/05/28 08:59

編集2019/05/29 00:44
gh640

総合スコア1407

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

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

champuyo

2019/05/28 10:36

> おそらく、 URL パラメータの pk を使って listData を絞り込む必要があるものと思います。PostCreateAndListView のどこかに次のような処理を入れる必要があるはずです。 処理の入れ方がわからず思考錯誤していますが、自分がやるべきことはなんとなくですが分かりました! ありがとうございます。 > まず ListView と CreateView の画面を別々に完成させて、それからそれらを組み合わせた画面を作る、とステップを刻んで実装されるのがよいと思います。 『ListView と CreateViewを多重継承して PostCreateAndListView を作る』 のとはまた違った意味なんでしょうか。 PostCreateAndListView の部分はネット上でソースをコピペしただけなので、自分でもよく理解出来ていません… [参考にしたページ]https://teratail.com/questions/170441 > 今回のような画面を作るときには function-based view を使った方がシンプル・かんたんに書けることが多いです。 そうなんですね! class-based view の方がシンプルでかんたんに書けるものだと単純に考えてしまっていました。 > もし「代わりにコードを書いてほしい」というご要望をお持ちであれば、他の方からの回答を待ってみてください。ご参考になれば幸いです。 「代わりにコードを書いてほしい」というのは願ったり叶ったりなんですが terateil の利用の仕方として「全然問題ないので最初からそれ目当ての質問でもok」なのか「善意でコードまで書いてくれる人もいるというだけに過ぎない」なのか分かりません。 今後また質問する時の参考として教えて頂けると嬉しいです! プログラミングに関する質問ではなくてごめんなさい。
gh640

2019/05/28 11:57

> 『ListView と CreateViewを多重継承して PostCreateAndListView を作る』 > のとはまた違った意味なんでしょうか。 そうですね、違った意味になるかどうかはわからないのですが、私が言いたかったのは 最終的には「 `ListView` と `CreateView` を多重継承したクラスを作る」というところに行き着くとしても、その前に `ListView` と `CreateView` を単独で使って「一覧ページ」と「新規作成ページ」を別個のページとして作る方が近道だと思います ということでした。それぞれのクラスがどう動くものなのか・どう使うものなのかを十分に理解しないままで、それらを組み合わせて使おうとするとかえって遠回りになると考えるからです。ご質問への回答になっていますか? > 「代わりにコードを書いてほしい」というのは願ったり叶ったりなんですが... 私が見た teratail の質問は高々数百件ですが、私が観測するかぎりでは後者の方に近いかなと思います。ただ、人によって teratail で回答する理由はさまざまでしょうし、そのあたりは回答する人次第で大きく変わる気もします。領域や質問の仕方等によっても変わってくるという印象です。 過去の質問を数十件〜百件ほどご覧になるとある程度そのあたりの傾向が把握できるかと思いますので、ご覧になってみてください。 がんばってください :D
champuyo

2019/05/28 15:16

> それぞれのクラスがどう動くものなのか・どう使うものなのかを十分に理解しないままで、それらを組み合わせて使おうとするとかえって遠回りになると考えるからです。 確かに、今回の場合も安易にコピペを利用してしまったせいで余計に理解が遅くなってしまっていました;; > 過去の質問を数十件〜百件ほどご覧になるとある程度そのあたりの傾向が把握できるかと思いますので、ご覧になってみてください。 人によって具体的なコードを出してくれたり、そもそもサンプルコードがあまり必要でない質問等もあるんですね。 今まで検索では出てこなかったけど自分と同じような質問をしている人も見つかったので、そういった意味でも過去の質問を見てみて良かったです! まだまだ時間がかかりそうですが、まずは頂いた回答を元に、関数ベースで投稿画面と一覧表示画面を分けたviewを作ろうと思っています。
gh640

2019/05/29 00:49

ご丁寧にコメントお戻しいただきありがとうございます。そうでしたか。それはよかったです :) 私の回答を後から読み返すとちょっと不親切な感じがしたので・・・ function-based view の書き方のイメージを回答本文に(「追記 1 」以下に)追記してみました。よろしければご覧になってみてください。 ( `post_list()` と `post_create()` を組み合わせるところはご自身でやられた方が理解が深まり後々よいのではないかと思いますが、どうしても厳しければおっしゃってください)
champuyo

2019/05/29 07:22

もうコメント返さないつもりだったのですが、上手い具合に(?)できたので感動して返信してしまいました。 言われた通り function-based view で実装したところ、まさに自分の理想通りの動きをしてくれました。 こんなに簡単にできるとは思っていませんでした!(ほぼコピペですが…) それでも class-based view よりも書いてあることが感覚的に理解しやすく、組み合わせる時も自分の中で納得しやすかったです。 初めての質問でしたが、ご丁寧に優しく教えていただける方で本当に良かったです。 ありがとうございました。
gh640

2019/05/30 02:52

ご丁寧にコメントお戻しくださりありがとうございます。 そうでしたか!それはよかったです :D 質問文の追記も拝見しました。とてもわかりやすくて他の方にも参考になると思います。 > それでも class-based view よりも書いてあることが感覚的に理解しやすく、組み合わせる時も自分の中で納得しやすかったです。 そうですか。そうお感じいただけたのであれば、私が「 class-based view が... function-based view が... 」のくだりでお伝えしたかったことは十分に感じていただけたのではないかと思います。 function-based view と class-based view にはそれぞれ長所・短所があるので、今後もページの内容や目的に応じてうまく使い分けてみてください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問