New Blog project - 2

[ New Blog project ]

  • Create, Update, Delete View를 구현한다.

    1. Views.py에 추가 작성한다.

      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
      class PostUpdate(UpdateView):
      model = Post
      template_name = 'post/post_update.html'
      fields = ['title','text','tag']
      # success_url => get_abslute_url

      from django.urls import reverse_lazy

      class PostDelete(DeleteView):
      model = Post
      template_name = 'post/post_delete.html'
      success_url = reverse_lazy('post:post_list')

      from django.utils.text import slugify

      class PostCreate(CreateView):
      model = Post
      template_name = 'post/post_create.html'
      fields = ['title', 'text', 'tag']

      def form_valid(self, form):
      # 작성자 매칭 - form.instance.author_id = self.request.user.id
      # 관리자 페이지에서만 title 값이 slug가 된다.
      # slugify를 사용해서 title의 값을 slug 값으로 한다.
      form.instance.slug = slugify(form.instance.title, allow_unicode=True)
      return super().form_valid(form)

      # tag 기능 구현
      from tagging.views import TaggedObjectList

      class PostTaggedObjectList(TaggedObjectList):
      model = Post
      allow_empty = True
      template_name = 'post/post_list.html'


      from django.views.generic import TemplateView

      class TagList(TemplateView):
      template_name = 'post/tag_list.html'
    2. urls.py에 경로를 추가한다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      from django.urls import path
      from .views import *

      app_name = 'post'

      urlpatterns = [
      path('tags/', TagList.as_view(), name='tag_list'),
      path('tags/<tag>/', PostTaggedObjectList.as_view(), name='post_taggedlist'),
      path('create/', PostCreate.as_view(), name='post_create'),
      path('delete/<int:pk>/', PostDelete.as_view(), name='post_delete'),
      path('update/<int:pk>/', PostUpdate.as_view(), name='post_update'),
      path('detail/<slug>/', PostDetail.as_view(), name='post_detail'),
      path('<category_slug>/', PostList.as_view(), name='post_list_with_category'),
      path('', PostList.as_view(), name='post_list')
      ]
    3. template 파일을 생성하고 작성한다.

        • post/templates/post/post_create.html
          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
          {% extends 'base.html' %}

          {% block title %}
          Create - {{object.title|truncatechars:15}}
          {% endblock %}

          {% block content %}
          <div class="row mt-3">
          <div class="col">
          {% include 'post/category_list.html' %}
          </div>
          <div class="col-8">
          <form action="" method="post">
          {% csrf_token %}
          {{form.media}}
          <table class="table table-striped">
          {{form.as_table}}
          </table>
          <input type="submit" class="btn btn-primary" value="Write">
          </form>
          </div>
          <div class="col"></div>
          </div>

          {% endblock %}
      • layout/base.html

        1
        2
        3
        4
        5
        6
         <!--// create 관련 기능 추가 //-->
        {% if user.is_authenticated %}
        <li class="nav-item">
        <a class="nav-link" href="{% url 'post:post_create' %}">Write</a>
        </li>
        {% endif %}
    • post/templates/post/post_update.html

      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
      {% extends 'base.html' %}

      {% block title %}
      Update - {{object.title|truncatechars:15}}
      {% endblock %}

      {% block content %}
      <div class="row mt-3">
      <div class="col">
      {% include 'post/category_list.html' %}
      </div>
      <div class="col-8">
      <form action="" method="post">
      {% csrf_token %}
      {{form.media}}
      <table class="table table-striped">
      {{form.as_table}}
      </table>
      <input type="submit" class="btn btn-primary" value="Update">
      </form>
      </div>
      <div class="col"></div>
      </div>

      {% endblock %}
    • post/templates/post/post_delete.html

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      {% extends 'base.html' %}

      {% block title %}
      Delete - {{object.title|truncatechars:15}}
      {% endblock %}

      {% block content %}
      <div class="row mt-3">
      <div class="col">
      {% include 'post/category_list.html' %}
      </div>

      <div class="col-8">
      <form action="" method="post">
      {% csrf_token %}
      <input type="submit" class="btn btn-danger" value="Delete">
      </form>
      </div>
      <div class="col"></div>
      </div>

      {% endblock %}
    • post/templates/post/post_detail.html

      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
      {% extends 'base.html' %}

      {% block title %}
      {{object.title|truncatechars:15}}
      {% endblock %}

      {% block content %}
      <div class="row mt-3">
      <div class="col">
      {% include 'post/category_list.html' %}
      </div>
      <div class="col-8">
      <div class="row" style="padding-bottom:3px; border-bottom:2px dashed #000000;">
      <div class="col-sm">
      <span style="color:red;">[{{object.category}}]</span>
      <span style="font-weight:bold;">{{object.title}}</span>
      </div>
      <div class="col-sm text-muted" style="text-align:right; font-size:0.9em;">{{object.formatcreated2}}</div>
      </div>
      <br>
      {{object.text|safe}}

      <!--// 태그 기능 추가 //-->
      {% load tagging_tags %}

      {% tags_for_object object as tags %}
      {% if tags %}
      Tags :
      {% for tag in tags %}
      <a href="{% url 'post:post_taggedlist' tag.name %}">#{{tag.name}}</a>
      {% endfor %}
      {% endif %}

      <!--// 수정, 삭제 기능 추가 //-->
      <div class="row" style="padding-bottom:3px; border-bottom:2px dashed #000000;">
      <div class="col-sm"></div>
      <div class="col-sm" style="text-align:right;">
      {% if user.is_authenticated %}
      <a href="{% url 'post:post_update' object.id %}">[수정]</a>
      <a href="{% url 'post:post_delete' object.id %}" style="color:red">[삭제]</a>
      {% endif %}
      </div>
      </div>
      <br>
      </div>
      <div class="col"></div>
      </div>
      {% endblock %}
    • post/templates/post/tag_list.html

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      <!--//
      tag list 출력
      자주 나오는 tag일수록 글자 사이즈가 크게 출력된다.
      //-->
      {% extends 'base.html' %}
      {% block title %}Tag List{% endblock %}

      {% block content %}
      {% load tagging_tags %}
      {% tag_cloud_for_model post.Post as post_tags with steps=9 min_count=1 distribution=log %}
      {% for tag in post_tags %}
      <a href="{% url 'post:post_taggedlist' tag.name %}" style="font-size:{{tag.font_size}}em;">{{tag}}</a>
      {% endfor %}
      {% endblock %}
  • Comment 앱을 생성해서 Comment 기능을 추가한다.

    1. comment 앱을 생성한다.

      1
      2
      3
      $ python manage.py startapp comment

      # 잊지말고 settings.py의 INSTALLED_APPS에 추가하자.
    2. models.py를 작성한다.

      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
      from django.db import models
      from django.contrib.auth import get_user_model
      from django.contrib.contenttypes.fields import GenericForeignKey
      from django.contrib.contenttypes.models import ContentType

      class Comment(models.Model):
      """
      1. 작성자
      2. 어떤 모델과의 관계가 있는지
      3. + 작성자가 없다면, 모델과의 관계가 없다면
      """
      author = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name='my_comments')

      # ContentType 사용
      content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
      object_id = models.PositiveIntegerField()
      content_object = GenericForeignKey('content_type', 'object_id')

      text = models.CharField(max_length=400)
      created = models.DateTimeField(auto_now_add=True)

      def formatcreated(self):
      return self.created.strftime('%Y.%m.%d. %H:%M')

      # migrate를 잊지 말자.
    3. admin.py를 작성한다.

      1
      2
      3
      4
      5
      6
      from django.contrib import admin

      # Register your models here.
      from .models import Comment

      admin.site.register(Comment)
    4. views.py를 작성한다.

      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
      from django.shortcuts import render

      from .forms import CommentForm
      from django.shortcuts import redirect
      from django.urls import resolve
      from urllib.parse import urlparse
      from .models import Comment
      from django.contrib import messages

      def add_comment(request):
      if not request.user.is_anonymous:
      comment_form = CommentForm(request.POST)
      comment_form.instance.author_id = request.user.id

      if comment_form.is_valid():
      comment_form.save()
      messages.add_message(request, messages.SUCCESS, "댓글을 작성하였습니다.")
      else:
      messages.add_message(request, messages.WARNING, "Comment Invalid")
      else:
      messages.add_message(request, messages.WARNING, "댓글은 로그인 사용자만 남길 수 있습니다.")

      referer = request.META['HTTP_REFERER']
      return redirect(referer)

      def delete_comment(request, pk):
      comment = Comment.objects.filter(pk=pk)
      if comment.exists() and comment[0].author == request.user:
      comment.delete()
      messages.add_message(request, messages.SUCCESS, "댓글을 삭제하였습니다.")
      else:
      messages.add_message(request, messages.WARNING, "댓글을 삭제할 수 없습니다.")

      referer = request.META['HTTP_REFERER']
      return redirect(referer)
    5. urls.py를 작성한다.

    • config/urls.py

      1
      2
      3
      4
      urlpatterns = [
      #...
      path('comment/', include('comment.urls')),
      ]
    • comment/urls.py

      1
      2
      3
      4
      5
      6
      7
      from django.urls import path
      from .views import *

      urlpatterns = [
      path('delete_comment/<int:pk>', delete_comment, name='delete_comment'),
      path('add_comment/', add_comment, name='add_comment'),
      ]
    1. template 파일을 생성하고 작성한다.
    • comment/templates/comment/show_comment.html

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      <form action="{% url 'add_comment' %}" method="post">
      {% csrf_token %}
      {{form.as_p}}
      <input type="submit" class="btn btn-outline-dark btn-sm" value="등록">
      </form>
      <br>
      <table class="table table">
      <tr>
      <th colspan="3" class="align-left" style="color:red">댓글 {{object_list.count}}</th>
      </tr>
      {% for object in object_list %}
      <tr>
      <td>
      <span style="font-weight:bold;">{{object.author.username}}</span>
      <span style="font-size:0.8em;" class="text-muted">{{object.formatcreated}}</span>
      {% if object.author == user %}
      <a href="{% url 'delete_comment' object.id %}" style="color:red"><small>[삭제]</small></a>
      {% endif %}
      <br>
      {{object.text}}
      </td>
      </tr>
      {% endfor %}
      </table>
    • layout/base.html

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      <!--// 댓글과 관련한 메세지 기능 추가 //-->
      <div class="row">
      <div class="col">
      {% if messages %}
      {% for message in messages %}
      <div class="alert alert-{{message.tags}}">{{message}}</div>
      {% endfor %}
      {% endif%}
      </div>
      </div>
    1. templatetags 파일을 생성하고 작성한다.
    • comment/templatetags/comment.py

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      from django.template.loader import render_to_string
      from django.contrib.contenttypes.models import ContentType

      from django.template import Library
      register = Library()

      from comment.forms import CommentForm
      from comment.models import Comment

      @register.simple_tag(takes_context=True)
      def show_comment(context, content_type, object_id):
      # 폼 만들기
      content_type = ContentType.objects.get_for_model(content_type)
      form = CommentForm(initial={'content_type':content_type, 'object_id':object_id})

      # 해당 하는 댓글 목록 뽑기
      comments = Comment.objects.filter(content_type=content_type, object_id=object_id).all()

      # 템플릿 렌더링
      return render_to_string('comment/show_comment.html',{'form':form, 'object_list':comments}, request=context['request'])
    • post/templates/post/detail.html에 comment 기능을 추가한다.

      1
      2
      {% load comment %}
      {% show_comment content_type=object object_id=object.id %}
Share