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

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

ただいまの
回答率

88.81%

Djangoで掲示板を作りたい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,622

champuyo

score 15

初めにご挨拶

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

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

前提・実現したいこと

現在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ディレクトリ)

from django.urls import path
from .views import ThreadListView,PostCreateAndListView

app_name = 'bbs'
urlpatterns = [
    path('thread/', ThreadListView.as_view(), name='thread'),
    path('thread/<int:pk>/', PostCreateAndListView.as_view(), name='post'),
]


views.py

from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.generic.edit import CreateView
from django.views.generic import ListView, DetailView 
from .models import Thread,Post
from .forms import ThreadForm, PostForm

class ThreadListView(ListView):
    model = Thread
    template_name = "bbs/thread.html"

class PostCreateView(CreateView):
    form_class = PostForm
    template_name = "bbs/post.html"
    success_url = reverse_lazy('bbs:post')    

class PostListView(ListView):
    model = Post

class PostCreateAndListView(PostCreateView,PostListView):
    def get(self, request, *args, **kwargs):
        formView = PostCreateView.get(self, request, *args, **kwargs)
        listView = PostListView.get(self, request, *args, **kwargs)
        formData = formView.context_data['form']
        listData = listView.context_data['object_list']
        context = {'form' : formData, 'post_list' : listData}
        return render(request, 'bbs/post.html', context)


forms.py

from django import forms
from .models import Thread,Post


class ThreadForm(forms.ModelForm):
    class Meta:
        model = Thread
        fields = ("subject",)

class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ("message",)


models.py

from django.db import models
from django.utils import timezone
from account.models import User


class Thread(models.Model):
    subject = models.CharField(max_length=255)

    def __str__(self):
        return self.subject

class Post(models.Model):
    thread = models.ForeignKey(Thread, on_delete=models.CASCADE, null=True, related_name='threads')
    message = models.TextField(max_length=3000)
    created_at = models.DateTimeField(auto_now_add=True)
    created_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='post', null=True)
    def __str__(self):
        return self.message


thread.html

{% extends 'home/base.html' %}

{% block content %}
    <div class="contents">
<ul>
    {% for item in object_list %}
    <li><a href="{% url 'bbs:post' pk=item.pk %}">{{ item }}</a></li>
    {% endfor %}
</ul>
    </div>


{% endblock %}


post.html

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>タイトル</title>
</head>
<body>
    <h1>掲示板だよ</h1>
    <ul>
    {% for post in post_list %}
        <li>本文:{{ post.message }}</li>
        <li>投稿日時:{{ post.created_at }}</li>
        <li>投稿者:{{ post.created_by }}</li>
    {% endfor %}
    </ul>
    <p>とうこうするよ</p>
    <form action="" method = "POST">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit">
    </form>
</body>
</html>

試したこと

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

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

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

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

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

頂いた回答を元に作成し直しました。

希望通りの動きをしています。

urls.py

from django.urls import path
from .views import ThreadListView,post_list

app_name = 'bbs'
urlpatterns = [
    path('thread/', ThreadListView.as_view(), name='thread'),
    path('thread/<int:pk>/', post_list, name='post'),
]

views.py

from django.shortcuts import redirect, render, get_object_or_404
from django.urls import reverse_lazy
#from django.views.generic.edit import CreateView
from django.views.generic import ListView #DetailView TemplateView
from .models import Thread,Post
from .forms import ThreadForm, PostForm

class ThreadListView(ListView):
    model = Thread    # Thread.objects.all()を裏側でやってくれてる
    template_name = "bbs/thread.html"

def post_list(request, pk):
    per_page = 10

    thread = get_object_or_404(Thread,pk=pk)
    post_list= Post.objects.filter(thread=thread)
    form = PostForm(request.POST or None)

    if form.is_valid():
        post = form.save(commit=False)
        post.thread = thread
        post.save()
        return redirect('bbs:post', pk=thread.pk)

    context = {'form': form, 'post_list': post_list}
    return render(request, 'bbs/post.html', context)
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • gh640

    2019/05/28 18:01

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

    キャンセル

  • champuyo

    2019/05/28 19:01

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

    キャンセル

回答 1

checkベストアンサー

0

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

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

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

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

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

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

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

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

追記 1

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

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

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

from django.core.paginator import Paginator
from django.shortcuts import get_object_or_404, render

from .models import Thread, Post


def post_list(request, pk):
    """特定のスレッドの投稿を一覧表示する

    引数の `pk` はスレッドの `pk` を指すので要注意
    """
    per_page = 20

    thread = get_object_or_404(Thread, pk=pk)
    post_list = Post.objects.filter(thread=thread)

    # ページめくり機能をサポートする
    # (ページめくり機能が不要な場合はこの 3 行は削除してください)
    paginator = Paginator(post_list, per_page)
    page = request.GET.get('page')
    post_list = paginator.get_page(page)

    context = {'post_list': post_list}
    return render(request, 'bbs/post.html', context)

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

from django.shortcuts import get_object_or_404, redirect, render

from .models import Thread
from .forms import PostForm


def post_create(request, pk):
    """特定のスレッドにひもづいた投稿を作成する

    引数の `pk` はスレッドの `pk` を指すので要注意
    """
    thread = get_object_or_404(Thread, pk=pk)
    form = PostForm(request.POST or None)

    # フォームが送信されて、なおかつその値が正しい場合は投稿データを登録してリダイレクト
    if form.is_valid():
        post = form.save(commit=False)
        post.thread = thread
        post.save()
        return redirect('bbs:post', pk=thread.pk)

    context = {'form': form}
    return render(request, 'bbs/post.html', context)

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

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

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

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

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/05/29 09:49

    ご丁寧にコメントお戻しいただきありがとうございます。そうでしたか。それはよかったです :)

    私の回答を後から読み返すとちょっと不親切な感じがしたので・・・ function-based view の書き方のイメージを回答本文に(「追記 1 」以下に)追記してみました。よろしければご覧になってみてください。

    ( `post_list()` と `post_create()` を組み合わせるところはご自身でやられた方が理解が深まり後々よいのではないかと思いますが、どうしても厳しければおっしゃってください)

    キャンセル

  • 2019/05/29 16:22

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

    キャンセル

  • 2019/05/30 11:52

    ご丁寧にコメントお戻しくださりありがとうございます。

    そうでしたか!それはよかったです :D 質問文の追記も拝見しました。とてもわかりやすくて他の方にも参考になると思います。

    > それでも class-based view よりも書いてあることが感覚的に理解しやすく、組み合わせる時も自分の中で納得しやすかったです。

    そうですか。そうお感じいただけたのであれば、私が「 class-based view が... function-based view が... 」のくだりでお伝えしたかったことは十分に感じていただけたのではないかと思います。 function-based view と class-based view にはそれぞれ長所・短所があるので、今後もページの内容や目的に応じてうまく使い分けてみてください。

    キャンセル

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

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

関連した質問

同じタグがついた質問を見る