djangoで掲示板つくってみた

2022年5月3日

djangoで掲示板つくってみた

表題の件の通りです。
今回はざっくり動画とコードだけですが掲載しておこうと思います。

削除/更新の機能は前回の「djangoでブログを作ってみる」で実装しているので割愛しておりますが、時間があったら実装しようかと思っています。

ログイン/ログアウトについては以前に記事にしておりますので「djangoでログイン機能を実装してみる」からお願いします。

動きは下の通りです。

urls.py


from django.urls import path
from . import views
#--ログインログアウト----------------------------------
from django.contrib.auth import views as auth_views
app_name = 'app'
urlpatterns = [
        path('', views.index, name='index'),
        path('display_threads/', views.display_threads, name='display_threads'),
        path('display_comments/<int:thread_id>/', views.display_comments, name='display_comments'),
        path('create_thread/', views.create_thread, name='create_thread'),
        path('create_comment/', views.create_comment, name='create_comment'),
        path('login/', auth_views.LoginView.as_view(template_name='app/login.html'), name='login'),
        path('logout/', auth_views.LogoutView.as_view(), name='logout'),
]

models.py


#--掲示板----------------------------------------------
class Thread(models.Model):
    title    = models.CharField(blank=False, null=False, max_length=150)
    content  = models.TextField(blank=False, null=False)
    user     = models.ForeignKey(User, on_delete=models.CASCADE)
    created_datetime = models.DateTimeField(auto_now_add=True)
    updated_datetime = models.DateTimeField(auto_now=True)
    def __str__(self):
        return self.title
class Comment(models.Model):
    comment = models.TextField(blank=False, null=False)
    user    = models.ForeignKey(User, on_delete=models.CASCADE)
    thread  = models.ForeignKey(Thread, on_delete=models.CASCADE)
    created_datetime = models.DateTimeField(auto_now_add=True)
    updated_datetime = models.DateTimeField(auto_now=True)
    def __str__(self):
        return self.comment
# [models.ForeignKey] - 紐づけるテーブル(モデル)のプライマリーキーが入る
# [フィールド名]  = models.ForeignKey([モデル名], ...)
# on_delete=models.CASCADE - 紐づくデータが削除されたら自身のレコードを削除する
# on_delete=models.PROTECT - 紐づくデータが削除されても自身のレコードを削除しない
# ※上記の場合Userが削除されたときにThreadのレコードを削除するか否か

forms.py


from django.forms import ModelForm
from .models import Thread
from .models import Comment
#--掲示板----------------------------------------------
class ThreadForm(ModelForm):
    class Meta:
        model  = Thread
        fields = ("title", "content")
class CommentForm(ModelForm):
    class Meta:
        model = Comment
        fields = ("comment",)

views.py


#--掲示板----------------------------------------------
def display_threads(request):
    threads = Thread.objects.all().values()
    count   = len(threads)
    for count in range(count):
        #掲示板投稿したユーザーのIDを元にユーザー名取得
        username_dicts = User.objects.filter(pk=threads[count]['user_id']).values('username')
        #ユーザー名を取得してオブジェクトに追加
        threads[count].update(username_dicts[0])
    #フォーム作成
    form = ThreadForm
    #ページャー作成
    paginator = Paginator(threads, 9)
    current_page = request.GET.get('current_page')
    threads = paginator.get_page(current_page)
    context = {
        'threads': threads,
        'form': form,
    }
    return render(request, 'app/display_threads.html', context)
@login_required
def create_thread(request):
    #入力値をフォームに追加
    form = ThreadForm(request.POST)
    #入力内容が正しければ
    if form.is_valid():
        #DBに登録する準備を行う
        thread = form.save(commit=False)
        #threadにログイン中ユーザー情報を追加
        thread.user = request.user
        #DBに登録
        thread.save()
        messages.success(request, "投稿が完了しました!")
    return redirect('app:display_threads')
def display_comments(request, thread_id):
    #該当する掲示板一件を取得
    threads = Thread.objects.filter(pk=thread_id).values()
    thread  = threads[0]
    username_dicts = User.objects.filter(pk=threads[0]['user_id']).values('username')
    thread.update(username_dicts[0])
    #該当する掲示板に紐づくコメントを取得
    comments = Comment.objects.filter(thread_id=thread_id).values()
    count = len(comments)
    #コメントのユーザーIDからユーザー名を取得してオブジェクトに追加
    for count in range(count):
        username_dicts = User.objects.filter(pk=comments[count]['user_id']).values('username')
        comments[count].update(username_dicts[0])
    #フォーム作成
    form = CommentForm
    context = {
        'thread': thread,
        'comments': comments,
        'form': form,
    }
    return render(request, 'app/display_comments.html', context)
@login_required
def create_comment(request):
    thread_id = request.POST['thread_id']
    #入力値をフォームに追加
    form = CommentForm(request.POST)
    #入力内容が正しければ
    if form.is_valid():
        #DBに登録する準備を行う
        comment = form.save(commit=False)
        #commentにログイン中ユーザー情報を追加
        comment.user = request.user
        comment.thread_id = thread_id
        #DBに登録
        comment.save()
        messages.success(request, "投稿が完了しました!")
    return redirect('app:display_comments', thread_id = thread_id)

base.html


{% load static %}
<!DOCTYPE html>
<html>
<head>
    <title>Django Practice</title>
    <script src="{% static 'js/jquery-3.5.1.min.js' %}"></script>
    <script src="{% static 'js/app.js' %}"></script>
    <link rel="stylesheet" type="text/css" href="{% static 'css/style.css' %}">
</head>
<body>
    <header>
        <div class="header_container">
            <h1><a href="{% url 'app:index' %}" class='header'>Django Practice</a></h1>
            <div class="header_menue">
            {% if request.user.is_authenticated %}
                <form method="get" action="{% url 'app:logout' %}">
                    <button type="submit" class="negative_button">logout</button>
                </form>
            {% else %}
                <form method="get" action="{% url 'app:login' %}">
                    <button type="submit" class="positive_button">login</button>
                </form>
            {% endif %}
            </div>
        </div>
    </header>
    <div class="container">
        {% block content %}{% endblock %}
    </div>
</body>
</html>

display_threads.html


{% extends 'app/base.html' %}
{% block content %}
{% load widget_tweaks %}
{% for thread in threads %}
<!--TABLE----------------------------------------->
<div class="linu_up_container">
    <table class="thread_container">
        <tr>
            <td class="thread_username">{{ thread.username }}</td>
            <td class="created_datetime">{{ thread.created_datetime }}</td>
        </tr>
        <tr>
            <td colspan="2" class="title">{{ thread.title }}</td>
        </tr>
        <tr>
            <td colspan="2" class="content">{{ thread.content | linebreaks | urlize }}</td>
        </tr>
        <tr>
            <td colspan="2" class="read_more"><a href="{% url 'app:display_comments' thread.id %}">read more</a></td>
        </tr>
    </table>
</div>
{% endfor %}
<!--CREATE---------------------------------------->
<form method="post" action="{% url 'app:create_thread' %}">{% csrf_token %}
    <div class="create_thread_container">
        <table class="thread_container clear_float">
            <tr>
                <td class="thread_username">{{ user.username }}</td>
            </tr>
            <tr>
                <td>{{ form.title | add_class:"form_title" }}</td>
            </tr>
            <tr>
                <td>{{ form.content | add_class:"form_content" }}</td>
            </tr>
            <tr>
                <td><button type="submit" class="positive_button">create</button></td>
            </tr>
        </table>
    <div>
</form>
<!--PAGE----------------------------------------->
<div class="pager">
    <!-- 前のページへのリンク -->
    {% if threads.has_previous %}
        <a class='pager_previous' href="?current_page={{ threads.previous_page_number }}">Previous</a>
    {% endif %}
    <!-- 現在のページ番号と全体のページ数 -->
    <span class='pager_number'>
        {{ threads.number }} / {{ threads.paginator.num_pages }}
    </span>
    <!-- 次のページへのリンク -->
    {% if threads.has_next %}
        <a class='pager_next' href="?current_page={{ threads.next_page_number }}">Next</a>
    {% endif %}
</div>
{% endblock %}

display_comments.html


{% extends 'app/base.html' %}
{% block content %}
{% load widget_tweaks %}
<table class="comment_container">
    <tr>
        <td class="comment_username">{{ thread.username }}</td>
        <td class="created_datetime">{{ thread.created_datetime }}</td>
    </tr>
    <tr>
        <td colspan="2" class="title">{{ thread.title }}</td>
    </tr>
    <tr>
        <td colspan="2" class="content">{{ thread.content | linebreaks | urlize }}</td>
    </tr>
</table>
{% for comment in comments %}
<table class="comment_container">
    <tr>
        <td class="comment_username">{{ comment.username }}</td>
        <td class="created_datetime">{{ comment.created_datetime }}</td>
    </tr>
    <tr>
        <td colspan="2" class="content">{{ comment.comment | linebreaks | urlize }}</td>
    </tr>
</table>
{% endfor %}
<!--CREATE---------------------------------------->
<form method="post" action="{% url 'app:create_comment' %}">{% csrf_token %}
    <input type="hidden" value="{{ thread.id }}" name="thread_id">
    <table class="comment_container">
        <tr>
            <td class="comment_username">{{ user.username }}</td>
        </tr>
        <tr>
            <td>{{ form.comment | add_class:"form_content" }}</td>
        </tr>
        <tr>
            <td><button type="submit" class="positive_button">create</button></td>
        </tr>
    </table>
</form>
{% endblock %}

感想

まだまだORMになれずSQLで書きたくなってしまいます。
今度ORMだけをまとめた記事でも書かないとなぁとか思っている今日この頃です。

2022年5月3日