2019.05.16 장고 댓글 기능 구현하기 함수형 뷰

댓글 기능 구현하기(함수형 뷰에서 구현하기)

  1. 모델이 있다고 꼭 그 모델의 뷰가 필요한 것은 아니다.

  2. 댓글 같은 경우 그 컨텐츠의 아래에 적히는 것이기 때문에 그 컨텐츠의 뷰에서 처리한다.

  3. 폼이 있어야 한다. form.py를 만들거나 템플릿에서 만들어줘야 한다.

  4. 한 뷰에서 처리하기(detail 뷰에서 처리하기)

    1. 모델 구현하기
    2. form.py 구현하기
    3. 뷰 구현하기
    4. 템플릿 구현하기
  5. 댓글 기능을 하나의 뷰로 빼서 처리하기

    1. 모델 구현하기
    2. form.py구현하기
    3. 뷰 구현하기
    4. 템플릿 구현하기
      1. form 의 action에 view를 연결하기 위해 url을 설정해줘야한다.
    5. url 연결해주기
      1. url을 뷰로 연결시켜준다.

모델 구현하기


class Comment(models.Model):
    document = models.ForeignKey(Document, on_delete=models.CASCADE, related_name='comments')
    author = models.ForeignKey(get_user_model(), on_delete=models.SET_NULL, null=True, blank=True, related_name='comments')
    text = models.TextField()
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    like = models.IntegerField(default=0)
    dislike = models.IntegerField(default=0)

    def __str__(self):
        return (self.author.username if self.author else "무명")+ "의 댓글"
  • get_user_model : 커스텀 모델 , 커스텀 USER를 넣거나 없으면 그냥 USER를 받음
  • author : models.SET_NULL : 연결된 foreignkey 즉 USER가 삭제되어도 Comment를 null로 바꾸고 남겨놓는다. 단 null=True가 필요하다.

form.py 구현하기

from .models import Document, Comment

class CommentForm(forms.ModelForm):
    #text = forms.TextInput(label = '댓글')

    class Meta:
        model = Comment
        fields = ['text']

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['text'].label = "댓글"
  • text필드를 댓글이라는 문구로 바꾸어 줄 수 있다.
  • text = forms.TextInput(label = '댓글') 혹은
  • 아래의 def _init_ 을 통해 구현하기

views.py 뷰 구현하기

document_detail 뷰에서 구현할 때

def document_detail(request, document_id):

    document = get_object_or_404(Document, pk=document_id)

    #만약 post일때만 댓글 입력에 관한 처리를 더한다.

    if request.method == "POST":
        comment_form = CommentForm(request.POST)
        comment_form.instance.author_id = request.user.id
        comment_form.instance.document_id = document_id
        if comment_form.is_valid():
            comment = comment_form.save()


    #models.py에서 document의 related_name을 comments로 해놓았다.

    comment_form = CommentForm()
    comments = document.comments.all()

    return render(request, 'board/document_detail.html', {'object':document, "comments":comments, "comment_form":comment_form})
  • detail에서는 get_object_or_404로 하나만 뽑아내야 하고 따라서 pk키도 필요하다.

    • list에서는 get_list_or_404로 전체를 뽑아낸다.
  • document.comments.all() 아래에 와야지 논리오류가 발생하지 않는다.

  • comment_form 의 위치에 따라서 글자가 바뀐다.

    • comment_form.save 아래에 위치하게 되면 저장된 상태로 그대로 넘어가서 정보가 남아있게 된다.
  • self.instance = 상속받은 객체 그 자체

댓글 기능 따로 빼서 구현하기


def comment(request, document_id):

    if request.method == "POST":
        comment_form = CommentForm(request.POST)
        comment_form.instance.author_id = request.user.id
        comment_form.instance.document_id = document_id
        if comment_form.is_valid():
            comment = comment_form.save()

    return HttpResponseRedirect(reverse_lazy('board:detail', args=[document_id]))

# get_absolute_url을 설정해 놓았을 시(in models)
    def get_absolute_url(self):
        return reverse('board:detail', args=[self.id])

 제일 마지막 문장    return redirect(document)로  대체가능
  • 하지만 이렇게 해주면 해당 뷰로 접근하기 위한 url이 필요하게 되고 탬플릿의 form에서 action에 url을 설정해줘야 한다.
  • 그리기 위해서 또 urls.py에 url을 연결하여 해당 views로 접근하도록 한다.
  • 그리고 그 뷰를 실행하고 redirect를 활용하여 detail 페이지로 가도록 구현해준다.

템플릿 구현하기

  • document_detail.html

{ % extends 'base.html' % }


{ % block content % }

{{object.title}} 

{{object.text}}

{{object.image.url}}

{{object.author.username}}



<form action="{ % url "board:comment" object.id % }" method="POST">
{ % csrf_token % }

    {{comment_form.as_p}}
    <input type="submit" value="Comment" class="btn btn-outline-primary">

</form>

<table class="table table-striped">
    { % for comment in comments % }
    <tr>
        <td>{{ comment.text }}</td>
        <td>{{ comment.author.username}}</td>
        <td>{{ comment.created }}</td>
        <td><a href="{ % url 'board:comment_delete' comment.id % }">삭제하기</a></td>
        <td><a href="{ % url 'board:comment_update' comment.id % }">수정하기</a></td>
    </tr>
    { % endfor % }
</table>

{ % endblock % }
  • 만들어 놓은 comment_form을 가지고 온다.
  • 댓글 기능을 따로 구현하였다면 위와 같이 form의 action이 필요하고 그렇지 않다면 없어도 된다.
  • comments를 돌면서 관련 댓글을 뽑아오는데 이 comments는 detail 뷰에서 받아왔다.
    • document = get_object_or_404(Document, pk=document_id) 를 통해 특정 document에 대한 것들만 다 가지고 온다음에
    • comments = document.comments.all()를 통해 해당 document의 comment를 모두 가지고 왔다.
  • 옛날에 나는 일단 모든 comment를 다 가지고 온 다음에 템플릿 단에서 각 객체들의 id를 비교하여 보여줄 수 있도록 했었고
  • 그 다음에는 filter를 통해 구현해보려고 헀었다.
  • 하지만 그럴 필요 없이 미리 document를 pk값으로 특정 document를 가지고 오고 그 모든 comment를 템플릿으로 넘겨줌으로서 해결 할 수 있다.

+ Recent posts