Django Section 7

yoodeit·2025년 8월 20일
0

일단 만드는 어무해

목록 보기
16/21

MIXIN으로 comment app 구현하는 시간입니다.

1. commentapp 시작하기

1) startapp commentapp

python manage.py startapp commentapp

2) settings.py

3) redjango/urls.py

4) commentapp/urls.py

dk dlrj durlafrh Kemfak

5) commentapp/models.py

from articleapp.models import Article
from django.contrib.auth.models import User
from django.db import models

# Create your models here.

class Comment(models.Model):
    article = models.ForeignKey(Article, on_delete=models.SET_NULL, null=True, related_name='comment')
    writer = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name='comment')
    content = models.TextField(null=False)

    created_at = models.DateField(auto_now=True)

6) commentapp/forms.py

from dataclasses import fields

from commentapp.models import Comment
from django.forms import ModelForm


class CommentCreationForm(ModelForm):
    class Meta:
        model = Comment
        fields = ['content']

7) makemigrations->migrate

2. commentapp create

1) commentapp/views.py

from commentapp.forms import CommentCreationForm
from commentapp.models import Comment
from django.shortcuts import render
from django.urls import reverse, reverse_lazy
from django.views.generic import CreateView

# Create your views here.

class CommentCreateView(CreateView):
    model = Comment
    form_class = CommentCreationForm
    template_name = 'commenetapp/create.hml'

    def get_success_url(self):
        return reverse('articleapp:detail', kwargs={'pk':self.object.article.pk})

    

2) URLS.PY

path('create/', CommentCreateView.as_view(), name='create'),

3) templates/create.html

{% extends 'base.html' %}
{% load django_bootstrap5 %}

{% block content %}

    <div style="text-align: center; max-width: 500px; margin: 4rem auto;">
        <div class="mb-4">
            <h1>Comment Create</h1>
        </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">
            <input type="hidden" name="article_pk" value="">
        </form>
    </div>

{% endblock %}

마찬가지로 create.html을 그대로 베껴오고 h1태그랑 form태그만 좀 바꿔준다.

또한 이런 식으로 hidden 인풋태그를 넣어둔다.

3. detail페이지에 comment합치기

여기서 mixin이 필요해진다.

1) detail.html에서 include

{% include 'commentapp/create.html' with article=target_article %}

2) create.html 수정

<input type="hidden" name="article_pk" value="{{ article.pk }}"> #이 값은 조작이 가능하다.

3) views.py articleDetailView에 mixin


이런 모습을 기대하겠지만...

실제로 서버를 켜서 돌려보면...

이런 에러가 발생한다. 아무래도 detailview에는 form이 없기 때문...

그래서 FormMixin을 사용하게 된다.

from django.views.generic.edit import FormMixin

class ArticleDetailView(DetailView, FormMixin):
    model = Article
    form_class = CommentCreationForm
    context_object_name = 'target_article'
    template_name = 'articleapp/detail.html'

4) commentapp/views.py

class CommentCreateView(CreateView):
    model = Comment
    form_class = CommentCreationForm
    template_name = 'commentapp/create.html'

    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)

    def get_success_url(self):
        return reverse('articleapp:detail', kwargs={'pk':self.object.article.pk})

    

5) 로그인 안하고 댓글다는 거 막기 in create.html

            {% if user.is_authenticated %}
            <input type="submit" class="btn btn-dark rounded-pill col-6 mt-3">
            {% else %}
            <a href="{% url 'accountapp:login %'}?next={{ request.path }}"
            class="btn btn-dark rounded-pill col-6 mt-3">
                Login
            </a>
            {% endif %}

5. comment 보이도록

1) articleapp/detail.html

2) commentapp/detail.html

<div style="border: 1px solid; text-align: left; padding: 4%; 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>


댓글 보이는 것까지는 구현 완료

댓글 삭제 delete view

1) commentapp/views.py

2) commentapp/details.html

<div style="border: 1px solid; text-align: left; padding: 4%; 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>

3) commentapp/urls.py

path('delete/<int:pk>', CommentDeleteView.as_view(), name='delete'),

4) decorator.py


from articleapp.models import Article
from commentapp.models import Comment
from django.http import HttpResponseForbidden


def comment_authorized(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

5) views.py에 달아주기

@method_decorator(comment_authorized,'get')
@method_decorator(comment_authorized,'post')
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})
profile
Yoodeit

0개의 댓글