Board project - 4

[ Board project ]

  • 댓글 기능 적용

    1. models.py에 comment 모델 작성

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      class Comment(models.Model):
      # Todo : 댓글 남기기를 위해서 Form
      # Todo : 뷰 처리는 Documents의 뷰

      # 해당 게시글의 댓글이기 때문에 document라는 ForeignKey 적용
      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) # ManyToMany
      dislike = models.IntegerField(default=0)

      def __str__(self):
      return (self.author.username if self.author else "무명") +"의 댓글"

      # makemigrations와 migrate를 실행하자.
    2. forms.py 작성

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      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 = "댓글"
      self.fields['text'].widget = forms.TextInput()
      self.fields['text'].widget.attrs = {'class': "form-control",
      'placeholder':"댓글을 입력하세요"}
    3. views.py 작성

    • 페이지에 접근했을 때 구동되는 로직들
      • 함수형 뷰(Function Based View)
        1. 해당 객체가 있는지 확인(get_object_or_404, object.filter.exists)
        2. 객체에 대한 권한 체크 - 작성자, 관리자
        3. get, post
          • get : 해당 페이지에 필요한 값 입력 받기
          • post : 입력받은 값에 대한 처리 -> 삭제, 업데이트
        4. 처리 후 페이지 이동
      • 클래스형 뷰(Class Based View)
        1. 객체에 대한 권한 체크(dispatch) - 작성자, 관리자
        2. 해당 객체가 있는지 확인(get_object, get_queryset)
        3. get, post
          • get : 해당 페이지에 필요한 값 입력 받기
          • post : 입력 받은 값에 대한 처리 -> 삭제, 업데이트
        4. 처리 후 페이지 이동
    • 함수형 뷰와 클래스형 뷰의 로직이 다른 것은 아니다.
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      # Comment 모델 추가
      from .models import Board, Category, Document, PhoneNumber, Comment

      # 접근 권한의 메시지 출력을 위한 messages 모듈 추가
      from django.contrib import messages

      # comment 생성 뷰 추가
      # detail 부분에서 comment를 생성하는 부분을 나눔
      def comment_create(request, document_id):
      document = get_object_or_404(Document, pk=document_id)
      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()

      # redirect(reverse('board:detail', args=[document_id]))

      # models.py의 document에서 get_absolute_url()을 지정
      return redirect(document)

      # comment 수정 뷰 추가
      def comment_update(request, comment_id):
      # 수정할 comment
      comment = get_object_or_404(Comment, pk=comment_id)
      # 수정할 cooment의 게시글
      document = get_object_or_404(Document, pk=comment.document.id)
      # user.is_staff
      # user.is_superuser

      # 현재 로그인 사용자가 comment의 작성자가 아니라면
      if request.user != comment.author:
      # '권한 없음'이라는 메시지 출력
      messages.warning(request, "권한 없음")
      return redirect(document)

      if request.method == "POST":
      # instance를 추가해야 새로 생성하는 것이 아닌 update인 것을 알 수 있다.
      form = CommentForm(request.POST, instance=comment)
      if form.is_valid():
      form.save()
      return redirect(document)
      else:
      form = CommentForm(instance=comment)
      return render(request, 'board/comment/update.html', {'form':form})

      # comment 삭제 뷰 추가
      def comment_delete(request, comment_id):
      comment = get_object_or_404(Comment, pk=comment_id)
      document = get_object_or_404(Document, pk=comment.document.id)

      # 조건
      # 1. 현재 로그인한 사용자가 comment 작성자가 아님
      # 2. 현재 로그인한 사용자가 관리자 권한이 아님
      # 3. 현재 로그인한 사용자가 게시글의 작성자가 아님
      if request.user != comment.author and not request.user.is_staff and request.user != document.author:
      messages.warning(request, "권한 없음")
      return redirect(document)

      if request.method == "POST":
      comment.delete()
      return redirect(document)
      else:
      return render(request, 'board/comment/delete.html', {'object':comment})

      # detail 페이지에서 comment 동작 처리
      # comment 생성을 처리할 수 있으나, comment_create라는 함수형 뷰를 따로 작성
      # detail와 연결된 tmplate 파일 안에서 comment를 생성하는 template 파일 부분을 나눔
      def document_detail(request, document_id):
      # document = Document.objects.get(pk=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()

      comment_form = CommentForm()
      # 현재 보고 있는 게시글의 comments들을 모두 불러옴
      comments = document.comments.all() # document 입장에서의 comments
      return render(request, 'board/document_detail.html', {'object':document,
      'comments':comments,
      'comment_form':comment_form})
    1. board/urls.py 작성

      1
      2
      3
      4
      5
      6
      7
      8
      9
      urlpatterns = [
      # 아래 항목 추가
      # comment 생성 관련
      path('create/<int:document_id>/', comment_create, name='comment_create'),
      # comment 수정 관련
      path('comment/update/<int:comment_id>/', comment_update, name='comment_update'),
      # comment 삭제 관련
      path('comment/delete/<int:comment_id>/', comment_delete, name='comment_delete'),
      ]
    2. template 파일 작성

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      <!--// templates/board/document_detail.html //-->
      {% extends 'base.html' %}
      {% block title %}
      Photo Detail
      {% endblock %}

      {% block content %}
      <div class="row">
      <div class="col"></div>
      <div class="col-6">
      {{object.title}} {{object.text}} {{object.image.url}} {{object.author.username}}<br>
      <hr>
      <!--// action에 comment_create 지정 //-->
      <form action="{% url 'board:comment_create' object.id %}" method="post" enctype="multipart/form-data">
      {% csrf_token %}
      {{comment_form.as_p}}
      <input type="submit" value="Comment" class="btn btn-outline-primary">
      </form>
      <!--// comment_list.html 적용 //-->
      <div id="docs_comment_list_area">
      {% include 'board/comment_list.html' %}
      </div>
      </div>
      <div class="col"></div>
      </div>
      {% endblock %}


      <!--// templates/board/comment_list.html //-->
      <table class="table table-strped">
      <thead>
      <tr>
      <th colspan="3" class="align-left">댓글 목록</th>
      </tr>
      </thead>
      {% for comment in comments %}
      <tr>
      <td>{{comment.text}}</td>
      <td>{{comment.author.username}}</td>
      <td>{{comment.created}}</td>
      <td><a href="{% url 'board:comment_update' comment.id %}" class="btn btn-outline-primary">Update</a></td>
      <td><a href="{% url 'board:comment_delete' comment.id %}" class="btn btn-outline-danger">Delete</a></td>
      </tr>
      {% endfor %}
      </table>


      <!--// templates/board/comment/update.html //-->
      {% extends 'base.html' %}
      {% block title %}
      Board Create
      {% endblock %}

      {% block content %}
      <div class="row">
      <div class="col"></div>
      <div class="col-6">
      <form action="" method="post" enctype="multipart/form-data">
      {% csrf_token %}
      {{form.as_p}}
      <input type="submit" value="Update">
      </form>
      </div>
      <div class="col"></div>
      </div>
      {% endblock %}


      <!--// templates/board/comment/delete.html //-->
      {% extends 'base.html' %}
      {% block title %}
      Board Create
      {% endblock %}

      {% block content %}
      <div class="row">
      <div class="col"></div>
      <div class="col-6">
      <form action="" method="post">
      <div class="alert alert-info">Do you want to delete {{object}}?</div>
      {% csrf_token %}
      <input type="submit" value="Delete" class="btn btn-outline-danger">
      </form>
      </div>
      <div class="col"></div>
      </div>
      {% endblock %}
    3. admin.py 작성

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      # Comment 추가
      from .models import Board,Category,Document,PhoneNumber, Comment

      # TabularInline 적용
      class CommentInline(admin.TabularInline):
      model = Comment

      # 관리자 페이지에서 ForeinKey로 연결된 데이터를 쉽게 관리하기 위해 추가
      # 현재 게시글 안에서 댓글 데이터 관리 용이
      class DocumentOption(admin.ModelAdmin):
      list_display = ['id', 'category', 'author', 'title', 'slug', 'created', 'updated']
      prepopulated_fields = {'slug':('title',)}
      inlines = [CommentInline]
Share