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
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 작성
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
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
{% load bootstrap4 %}
{% block content %}
{% endblock %}
테스트
위처럼 comment 가 단독으로 나오는것이 아닌, 게시글 밑에다가 comments 를 달아주도록 하기 위해서 include 구문을 사용하여 commentapp 의 create.html 내용을 가져와야 한다.
{% include 'commentapp/create.html' with article=target_article %}
이 경우 FormMixin 을 사용해야하는데 아래에서 볼 수 있듯 articleapp/view.py 에서 detailview 에 form 이 없기 때문에 오류가 난다.
따라서 앞서 배웠던 것처럼 FormMixin 을 추가 수정 -> 게시글 밑에 comment 가 추가됬다.
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 %}
<input type="hidden" name="article_pk" value="{{ article.pk }}">
</form>
{% endblock %}