Commentapp implementation

31206 ワード

実用主義プログラマーのインフラストラクチャコースを受講して作成しました.
ソース:https://www.inflearn.com/course/%EC%9E%A5%EA%B3%A0-%ED%95%80%ED%84%B0%EB%A0%88%EC%8A%A4%ED%8A%B8/lecture/62871?tab=note&speed=1.25

Comment App

  • Create/Delete View
  • Success_url to related article
  • モデル(記事は何ですか/著者は誰ですか/コンテンツコメントは何ですか/作成はいつですか)
  • Mixinとは?FormとしてDetailviewを使いたい場合は、Mixinを利用する必要があります.Form Mixinを使用してform classを指定したり、detailビューでformを使用したりできます.
  • python manage.py startapp commentappによるcommentapp
  • の作成
  • settingsとurlにcommentappとpathを追加
        path('comments/', include('commentary.urls')),
  • urls.py作成
  • from django.urls import path
    
    from commentapp.views import CommentCreateView
    
    app_name = 'commnetapp'
    
    urlpatterns = [
        path('create/', CommentCreateView.as_view(), name='create')
    ]
  • models.pyからCommentモデル
  • を作成する
    from django.contrib.auth.models import User
    from django.db import models
    
    # Create your models here.
    from articleapp.models import Article
    
    
    class Comment(models.Model):
        article = models.ForeignKey(Article, on_delete=models.SET_NULL, null=True, related_name='commnet')
        writer = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name='commnet')
    
        content = models.TextField(null=False)
    
        created_at = models.DateTimeField(auto_now=True)
  • views.py
  • from django.shortcuts import render
    
    # Create your views here.
    from django.views.generic import CreateView
    
    from commentapp.models import Comment
    
    
    class CommentCreateView(CreateView):
        model = Comment
        form_class = CommentCreationForm
        template_name = 'commentapp/create.html'
    
        def get_success_url(self):
            return reverse('articleapp:detail', kwargs={'pk': self.object.article.pk})
  • forms.py作成
  • from django.forms import ModelForm
    
    from commentapp.models import Comment
    
    
    class CommentCreationForm(ModelForm):
        class Meta:
            model = Comment
            fields = ['content']
  • 移行ジョブ
  • python manage.py makemigrations
    python manage.py migrate
    
  • create.html
  • <!--{% extends 'base.html' %}-->
    <!--나중에 articleapp/detail.html에서 불러와서 쓸 것이기 때문에 
    거기서도 base.html을 extends 하기 때문에 여기서는 지워준다.-->
    {% load bootstrap4 %}
    
    
    {% block content %}
    
        <div style="text-align: center; max-width: 500px; margin: 4rem auto">
            <div class="mb-4">
                <h4>
                    Comment Create
                </h4>
            </div>
            <form action="{% url 'commentapp:create' %}" method="post">
                {% csrf_token %}
                {% bootstrap_form form %}
    
                <input type="submit" class="btn btn-dark rounded-pill col-6 mt-3">
              <!--            현재 article의 pk 값을 얻어와서 나중에 article detail에 넘겨준다.-->
                <input type="hidden" name="article_pk" value="{{ article.pk }}">
            </form>
        </div>
    
    {% endblock %}

    しかし、コメントを書くためには新しいページに入るのではなく、投稿にコメントを書く必要があります.
    articleapp/templates/articleapp/detail.htmlにそのページをincludeで埋め込みます.
                {% include 'commnetapp/create.html' with article=target_article %}
    
    articlipp/viewもあります.pyでDetailViewを表示する場合、Formはありません.FormMixinをインポートして多重継承を行います.
    class ArticleDetailView(DetailView, FormMixin):
        model = Article
        form_class = CommentCreationForm
        context_object_name = 'target_article'
        template_name = 'articleapp/detail.html'

    このように完了するのではなく、サーバ上で設定する必要があります.
    commentapp/views.py
    class CommentCreateView(CreateView):
    
        def form_valid(self, form):
            temp_comment = form.save(commit=False)
            temp_comment.article = Article.objects.get(pk=self.request.POST['article_pk'])
            temp_comment.writer = self.request.user
            temp_comment.save()
            return super().form_valid(form)
    これまでは、commentapp/createがログインコメントを要求するボタンのみがログイン時に表示され、ログインしていない場合はログインウィンドウに移動します.
                {% if user.is_authenticated %}
                <input type="submit" class="btn btn-dark rounded-pill col-6 mt-3">
                {% else %}
    <!--            next를 통해 어디로 되돌아 와야 하는지도 설정해준다.-->
                <a href="{% url 'accountapp:login' %}?next={{ request.path }}"
                    class="btn btn-dark rounded-pill col-6 mt-3">
                    Login
                </a>
                {% endif %}
    あなたが書いたコメントを見てみましょう.
    articleapp/templates/articleapp/detail.html
                {% for comment in target_article.comment.all %}
                    {% include 'commentapp/detail.html' with comment=comment %}
                {% endfor %}
    commentapp/templates/commentapp/detail.htmlの生成
    <div style="border: 1px solid; text-align: left; padding: 4%; margin: 1rem 0; border-radius:1rem;
            border-color: #bbb;">
        <div>
            <strong>
                {{ comment.writer.profile.nickname }}
            </strong>
            &nbsp&nbsp&nbsp
            {{ comment.created_at }}
        </div>
    
        <div style="margin: 1rem 0">
            {{ comment.content }}
        </div>
    </div>
    コメントを削除する機能が実装されました.
    commentapp/views.py
    class CommentDeleteView(DeleteView):
        model = Comment
        context_object_name = 'target_comment'
        template_name = 'commentapp/delete.html'
    
        def get_success_url(self):
            return reverse('articleapp:detail', kwargs={'pk': self.object.article.pk})
    
    commentapp/delete.htmlを生成します.
    <div style="border: 1px solid; text-align: left; padding: 4%; margin: 1rem 0; border-radius:1rem;
            border-color: #bbb;">
        <div>
            <strong>
                {{ comment.writer.profile.nickname }}
            </strong>
            &nbsp&nbsp&nbsp
            {{ comment.created_at }}
        </div>
    
        <div style="margin: 1rem 0">
            {{ comment.content }}
        </div>
        {% if comment.writer == user %}
        <div style="text-align: right">
            <a href="{% url 'commentapp:delete' pk=comment.pk %}"\\
                class="btn btn-danger rounded-pill">
                Delete
            </a>
        </div>
        {% endif%}
    </div>
    commentapp/detail.htmlに削除リンクを追加します.
        <div style="text-align: right">
            <a href="{% url 'commentapp:delete' pk=comment.pk%}">
                Delete
            </a>
        </div>
    urlももちろん入れます.
    commentapp/urls.py
        path('delete/<int:pk>', CommentDeleteView.as_view(), name='delete')
    
    この削除ボタンを常に表示することはできません.そのコメントを書いたユーザーにしか見られないようにします.
        {% if comment.writer == user %}
    		...
        {% endif%}
    decoratorsはdelete viewにも適用され、コメントの持ち主を確認することができます.pyを生成して適用します.
    commentapp/decorators.py
    from django.contrib.auth.models import User
    from django.http import HttpResponseForbidden
    
    from commentapp.models import Comment
    
    
    def comment_ownership_required(func):
        def decorated(request, *args, **kwargs):
            comment = Comment.objects.get(pk=kwargs['pk'])
            if not comment.writer == request.user:
                return HttpResponseForbidden()
            return func(request, *args, **kwargs)
        return decorated