작정하고 장고 37강 - Mixin 소개 및 Commentapp 구현

IkSun·2023년 6월 26일

작정하고 장고

목록 보기
37/46

Mixin

  • CreateView 에서는 form 이 있고, DetailView 에서는 object 가 있다.
  • CreateView 에서는 object 가 없고, DetailView 에서는 form 이 없다.

만약 DetailView 를 Form 과 같이 사용하고 싶다면?

-> 문제가 발생한다

  • 위에는 article content 가 들어가고 밑에는 comment form 이 들어가야 한다.
  • 이떄 DetailView 에서는 form 이 없기 떄문에 발생하는 문제를 Mixin 에서 해결한다.
  • 따라서, FormMixin 를 상속받아 사용하게 된다면 Detail View 에서도 Form 을 사용할 수 있게 된다.

CommentApp 의 요건

  • 1) 댓글이 어떻게 시각화 될것인지 레이아웃을 간단하게 html 파일로 만들기

  • 2) 댓글을 달았을 때 그 게시물로 돌아가도록 설정

  • 3) 모델을 구성하는 정보들은 어떤 게시글에 달려있는 댓글인지, 댓글 글쓴이가 누구인지, 댓글 내용이 어떤지, 언제 만들어졌는지를 구현


Commentapp 만들기

#Terminal
python manage.py startapp commentapp

#/pragmatic/pragmatic/settings.py 
INSTALLED_APPS = [
	...
    'commentapp', # 추가
]

#/pragmatic/pragmatic/urls.py
urlpatterns = [
	...
    path('comments/', include('commentapp.urls')), # 추가
]

models.py 작성

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

from articleapp.models import Article


# Create your models here.

class Comment(models.Model):
    # article, writer 둘 다 서버단에서 확인을 하기 위해 추가적인 hidden input 을 추가해야한다.
    # -> create.html 에 <input type="hidden" name="article_pk" value=""> 부분 추가
    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)  # content 는 입력을 받을 것

    created_at = models.DateTimeField(auto_now=True)    # created_at 은 자동으로 생성될 것  

forms.py 작성

from django.forms import ModelForm

from commentapp.models import Comment

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

migration 작업

  • model 을 만들었으니 migration 작업 수행 후 서버 실행
python manage.py makemigrations
python manage.py migrate
python manage.py runserver

views.py 작성

# view 작성
from django.shortcuts import render
from django.urls import reverse
from django.views.generic import CreateView

from commentapp.forms import CommentCreationForm
from commentapp.models import Comment


# Create your views here.


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})

commentapp 의 urls.py

#/pragmatic/commentapp/urls.py
from django.urls import path

from commentapp.views import CommentCreateView

app_name = 'commentapp'

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

create.html

<!--{% extends 'base.html' %} 두번 html 을 가져오기 때문에 이부분은 생략-->
{% load bootstrap4 %}

{% block content %}

  <div style="text-align : center; max-width: 500px; margin: 4rem auto;">
    <div class="mb-4"> <!-- margin bottom 해서 4배 -->
      <h4>Comment Create</h4>
    </div>
    <form action="{% url 'commentapp:create' %}" method="post">  <!--url 일원화, 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="{{ article.pk }}">
    </form>
  </div>

{% endblock %}

테스트

  • 위처럼 comment 가 단독으로 나오는것이 아닌, 게시글 밑에다가 comments 를 달아주도록 하기 위해서 include 구문을 사용하여 commentapp 의 create.html 내용을 가져와야 한다.
<!--/Users/seonik/PycharmProjects/pragmatic/articleapp/templates/articleapp/detail.html -->

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

<!-- 이후 create 안에서 article 이라는 변수를 사용할 수 있게 된다 -->
<!--숨겨서 보내는 article pk 의 value 에 {{ article.pk }} 를 담아서 보내도록 수정 -->
  • 이 경우 FormMixin 을 사용해야하는데 아래에서 볼 수 있듯 articleapp/view.py 에서 detailview 에 form 이 없기 때문에 오류가 난다.
    따라서 앞서 배웠던 것처럼 FormMixin 을 추가 수정 -> 게시글 밑에 comment 가 추가됬다.

views.py 추가 작성

# /pragmatic/commentapp/views.py

from django.urls import reverse
from django.views.generic import CreateView

from articleapp.models import Article
from commentapp.forms import CommentCreationForm
from commentapp.models import Comment

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})

로그인한 계정만 코멘트를 달 수 있도록 수정

  • 로그인이 되어있을 경우만 submit 버튼을 보여주도록 하고, 그게 아니라면 로그인 url 로 향하는 링크를 걸어두기
{% load bootstrap4 %}

{% block content %}

  <div style="text-align : center; max-width: 500px; margin: 4rem auto;">
    <div class="mb-4"> <!-- margin bottom 해서 4배 -->
      <h4>Comment Create</h4>
    </div>
    <form action="{% url 'commentapp:create' %}" method="post">  <!--url 일원화, post 방식 으로 전송 -->
      {% csrf_token %}
      {% bootstrap_form form %}
      
      <!-- 추가 -->
      {% 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 %}
      <!---->

      <input type="hidden" name="article_pk" value="{{ article.pk }}">
    </form>
  </div>

{% endblock %}

commit

profile
공부한 것 기록용

0개의 댓글