코딩공부/홈페이지 만들기

Django로 홈페이지 만들기 - #8 좋아요, like

integerJI 2020. 5. 4. 16:04


참고 사이트

보고 배운 곳

https://code1018.tistory.com/250?category=987693

 

https://wayhome25.github.io/django/2017/03/01/django-99-my-first-project-4/

 

오늘 사용한 App

myApp

 

사용한 명령어

python manage.py makemigrations

python manage.py migrate

 

포인트

 

좋아요도 댓글과 비슷하다고 생각하면 된다.

한 명의 유저는 여러 개 시글을 좋아요 할 수 있다.

이를 이용하면 저장하기 기능을 사용할 수 있다.

본격 django와 ajax 사용

 

완성된 git ( 2020.06.18 키 노출로 인한 git 비공개 )

https://github.com/integerJI/int_1

 

aws key 노출되다.

https://integer-ji.tistory.com/200

 

aws key 생성시 주의 할점

https://integer-ji.tistory.com/208


사용한 디렉터리 계층구조 및 파일


myApp

# myProject/myApp/models.py

class Post(models.Model):
    main_text = models.CharField(max_length=200)
    create_user = models.ForeignKey(User, on_delete = models.CASCADE)
    create_date = models.DateTimeField('date published', default=timezone.now)
    create_img = models.ImageField(blank=True, upload_to="post/%Y/%m/%d", null=True)
#★    post_likes = models.ManyToManyField(User, related_name='post_likes')

    def __str__(self):
        return self.main_text

# ... new
    @property
    def total_likes(self):
        return self.post_likes.count()
# myProject/myApp/urls.py

path('like', views.like, name='like'),
# myProject/myApp/views.py

from .models import Post, Comment
try:
    from django.utils import simplejson as json
except ImportError:
    import json
from django.http import HttpResponse, HttpResponseRedirect
from django.views.decorators.http import require_POST

@login_required
@require_POST
def like(request):
    if request.method == 'POST':
        user = request.user 
        create_user = request.POST.get('pk', None)
        post = get_object_or_404(Post, id=create_user)

        if post.post_likes.filter(id = user.id).exists():
            post.post_likes.remove(user) 
            message = '좋아요 취소'
        else:
            post.post_likes.add(user)
            message = '좋아요!'

    context = {'likes_count' : post.total_likes, 'message' : message}
    return HttpResponse(json.dumps(context), content_type='application/json')
<!-- myProject/myApp/templates/index.html -->

{% extends 'base.html' %}
{% block content %}
<head>
  <style>
    .hidden {
      display: none
    }
  </style>
</head>
<body>
  <main role="main" class="container">
    <div class="row justify-content-center">
      <div class="col-md-7 blog-main">
        <div class="container">
          {% for post in posts.all %}
          <div class="card-deck mb-3">
            <div class="card mb-4 shadow-sm">
              <div class="card-header">

                  <!-- 접속자와 글쓴이가 같으면 -->
                  <div class="btn-group" style="float: left;">
                    <a class="my-0 font-weight-normal" href="{% url 'userpage' post.create_user %}"><span class="writer_name">{{ post.create_user }}</span></a>
                  </div>

                  <!-- 점속자와 글쓴이가 같지 않으면 사라짐 -->
                  <div class="btn-group" style="float: right;">
                    <span class="hidden" id="control_id">
                      <a href="{% url 'update' post.id %}"><img src="/static/update.png" alt="update" style="width: 1.5rem; height:1.5rem;">&nbsp;</a>
                      <a href="{% url 'delete' post.id %}"><img src="/static/delete.png" alt="delete" style="width: 1.5rem; height:1.5rem;"></a>
                    </span>
                  </div>

              </div>
              {% if post.create_img %}
              <div class="text-center">
                <img src="{{post.create_img.url}}" class="rounded" alt="..." width="585.5dp" height="585.5dp">
              </div>
              {% else %}
              <a>no</a>
              {% endif %}
              <div class="card-body">
              
              # ... new
              
                {% if post.post_likes.all %}
                <a class="like" name="{{ post.pk }}"><img id="like-img{{ post.pk }}" src="/static/like_after.png" alt="클릭시 좋아요 취소" style="width: 2rem; height:2rem;"></a>
                {% else %}
                <a class="like" name="{{ post.pk }}"><img id="like-img{{ post.pk }}" src="/static/like_before.png" alt="클릭시 좋아요" style="width: 2rem; height:2rem;"></a>
                {% endif %}

                <a href="{% url 'detail' post.id %}"><img src="/static/detail.png" alt="detail 이동" style="width: 2rem; height:2rem;"></a>
                <div class="group">
                <br>
                <small class="text-muted"><span class="like_count" id="count{{ post.pk }}">{{ post.total_likes }} like</span></small>
                <small class="text-muted">/</small>
                <small class="text-muted">{{post.comments.count}} comment</small>
                <br>
                <a class="my-0 font-weight-normal" href="{% url 'userpage' post.create_user %}">{{ post.create_user }}</a>
                <a class="card-title pricing-card-title">{{ post|safe|linebreaksbr }}</a>
                <br>
                {% for comment in post.comments.all %}
                <a class="card-text" href="{% url 'userpage' comment.comment_user %}"><span class="comment_writer_name">{{comment.comment_user}}</span></a>
                <a class="card-text">{{comment.comment_text}}
                  <span class="control hidden" id="control_id1{{ forloop.counter0 }}">
                  <form action="{% url 'c_delete' post.pk comment.pk %}" method="POST" style="display:inline-block">
                    {% csrf_token %}
                    <input type="`" name="app_url" id="app_url" value="{{app_url}}" />
                    <button type="submit">삭제</button>
                  </form>
                  </span>
                  <br>
                  {% endfor %}
                  <small class="text-muted">{{ post.create_date }}</small>
                </div>
                <br>
                <div class="group">

                  <form action="{% url 'c_post' post.id %}" method="POST">
                    {% csrf_token %}
                    <div class="input-group input-group-sm mb-3">
                      <input type="text" class="form-control" aria-label="Sizing example input" aria-describedby="inputGroup-sizing-sm" name="comment_text" id="comment_text" placeholder="댓글 달기 ..." style="display:inline-block">
                      <input type="hidden" name="app_url" id="app_url" value="{{app_url}}" />
                      <div class="input-group-prepend">
                        <button class="input-group-text" id="inputGroup-sizing-sm" type="submit">게시</button>
                      </div>
                    </div>
                  </form>
                </div>
              </div>
            </div>
          </div>
          {% endfor %}
        </div>
      </div>

      <aside class="col-md-3 blog-sidebar">
        <div class="card mb-3 bg-light rounded" style="max-width: 540px;" bg-light rounded>
          <div class="row no-gutters">
            <a></a>
            <div class="col-md-5 d-flex align-items-center d-flex justify-content-center">
              <img src="{{ profile_pic }}" alt="..." class="rounded-circle" width="60" height="60">
            </div>
            <div class="col-md-6">
              <div class="card-body">
                <a><span id="user_name">{{user.username}}</span></a>
                <br>
                <a href="{% url 'mypage' %}">My Profile</a>
                <br>
                <a href="{% url 'post' %}">New Post</a>
              </div>
            </div>
          </div>
        </div>
          {% if messages %}
            <div class="alert alert-warning alert-dismissible fade show" role="alert">
          {% for message in messages %}
            <strong>{{ message.message }}</strong>
          {% endfor %}
            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
              <span aria-hidden="true">&times;</span>
            </button>
            </div>
          {% endif %}
        <div class="p-3">
          <h4 class="font-italic">Producer</h4>
          <ol class="list-unstyled">
            <li><a href="https://github.com/integerJI">GitHub</a></li>
            <li><a href="https://www.instagram.com/integer_ji/">Instagram</a></li>
          </ol>
          <footer class="my-2 pt-2 text-muted text-center text-small">
            <p class="mb-1">&copy; 2019-2020 Integer Ji</p>
          </footer>
        </div>
      </aside>
      
    </div>
  </main>



  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  <script type="text/javascript">

    $("#user_name").text()
    $(".writer_name").text()

    $(".writer_name") 
    $(".writer_name")[0].innerHTML
    
    for (i = 0; i < $(".writer_name").length; i++) {
      if ($("#user_name").text() == $(".writer_name")[i].innerHTML) {
        $("#control_id").removeClass("hidden");
      }
    }

	# ... new

    $('.like').click(function () {
      var pk = $(this).attr('name')

      $.ajax({
        type: "POST",
        url: "{% url 'like' %}",
        data: { 'pk': pk, 'csrfmiddlewaretoken': '{{ csrf_token }}' },
        dataType: "json",

        success: function (response) {
          if (response.likes_count == 1) {
            $('#count' + pk).html(response.likes_count + ' like ');
            $('#like-img' + pk).attr('src', '/static/like_after.png');
          } else if (response.likes_count == 0) {
            $('#count' + pk).html('0 like');
            $('#like-img' + pk).attr('src', '/static/like_before.png');
          } else {
            $('#count' + pk).html(response.likes_count + ' like');
            $('#like-img' + pk).attr('src', '/static/like_after.png');
          }
          alert(response.message);
        },
        error: function (request, status, error) {
          alert('로그인이 필요합니다.')
        }
      });
    })
    
  </script>

</body>
{% endblock %}
<!-- myProject/myApp/templates/detail.html -->

{% extends 'base.html' %}
{% block content %}

<head>
    {% if messages %}
    <div class="alert alert-warning alert-dismissible fade show" role="alert">
        {% for message in messages %}
        <strong>{{ message.message }}</strong>
        {% endfor %}
        <button type="button" class="close" data-dismiss="alert" aria-label="Close">
            <span aria-hidden="true">&times;</span>
        </button>
    </div>
    {% endif %}
</head>

<body>
    <main role="main" class="container">
        <div class="row justify-content-center">

            <div class="col-md-7 blog-main">
                <div class="container">
                    <div class="card-deck mb-3">
                        <div class="card mb-4 shadow-sm">
                            {% if post.create_img %}
                            <div class="text-center">
                                <img src="{{post.create_img.url}}" class="rounded" alt="..." width="585.5dp"
                                    height="585.5dp">
                            </div>
                            {% else %}
                            <a>no</a>
                            {% endif %}
                        </div>
                    </div>
                </div>
            </div>

            <aside class="col-md-3 blog-sidebar">
                <div class="card-header">
                    <div class="d-flex justify-content-between align-items-center">
                        <div class="btn-group">
                            <a class="my-0 font-weight-normal" href="{% url 'userpage' post.create_user %}"><span
                                    class="writer_name">{{ post.create_user }}</span></a>
                        </div>
                        <div class="btn-group">
                            <span class="hidden" id="control_id">
                                <a href="{% url 'update' post.id %}"><img src="/static/update.png" alt="update"
                                        style="width: 1.5rem; height:1.5rem;">&nbsp;</a>
                                <a href="{% url 'delete' post.id %}"><img src="/static/delete.png" alt="delete"
                                        style="width: 1.5rem; height:1.5rem;"></a>
                            </span>
                        </div>
                    </div>
                </div>
                <div class="card-body">
                
                # ... new
                
                    {% if post.likes.all %}
                    <a class="like" name="{{ post.pk }}"><img id="like-img{{ post.pk }}" src="/static/like_after.png"
                            alt="클릭시 좋아요 취소" style="width: 2rem; height:2rem;"></a>
                    {% else %}
                    <a class="like" name="{{ post.pk }}"><img id="like-img{{ post.pk }}" src="/static/like_before.png"
                            alt="클릭시 좋아요" style="width: 2rem; height:2rem;"></a>
                    {% endif %}

                    <a href="{% url 'detail' post.id %}"><img src="/static/detail.png" alt="detail 이동"
                            style="width: 2rem; height:2rem;"></a>

                    <br>
                    <small class="text-muted"><span class="like_count" id="count{{ post.pk }}">{{ post.total_likes }}
                            like</span></small>
                    <small class="text-muted">/</small>
                    <small class="text-muted">{{post.comments.count}} comment</small>
                    <hr>
                    <a class="card-title pricing-card-title">{{ post|safe|linebreaksbr }}<small
                            class="text-muted">&nbsp;&nbsp;{{ post.create_date }}</small></a>
                    <hr>
                    {% for comment in post.comments.all %}
                    <a class="card-text" href="{% url 'userpage' comment.comment_user %}"><span
                            class="comment_writer_name">{{comment.comment_user}}</span></a>
                    <small class="text-muted">{{comment.comment_date}}</small>
                    <br>
                    <a class="card-text">{{comment.comment_text}}
                        <span class="control hidden" id="control_id1{{ forloop.counter0 }}">
                            <form action="{% url 'c_delete' post.pk comment.pk %}" method="POST"
                                style="display:inline-block">
                                {% csrf_token %}
                                <input type="hidden" name="app_url" id="app_url" value="{{app_url}}" />
                                <button type="submit">삭제</button>
                            </form>
                        </span>
                        <br>
                        {% endfor %}
                        <form action="{% url 'c_post' post.id %}" method="POST">
                            {% csrf_token %}
                            <div class="input-group input-group-sm mb-3">
                                <input type="text" class="form-control" aria-label="Sizing example input"
                                    aria-describedby="inputGroup-sizing-sm" name="comment_text" id="comment_text"
                                    placeholder="댓글 달기 ..." style="display:inline-block">
                                <input type="hidden" name="app_url" id="app_url" value="{{app_url}}" />
                                <div class="input-group-prepend">
                                    <button class="input-group-text" id="inputGroup-sizing-sm" type="submit">게시</button>
                                </div>
                            </div>
                        </form>
                </div>
            </aside>

        </div>
    </main>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <script type="text/javascript">

        $("#user_name").text()
        $(".writer_name").text()

        if ($("#user_name").text() == $(".writer_name").text()) {
            $("#control_id").removeClass("hidden")
        }

		# ... new

        $('.like').click(function () {
            var pk = $(this).attr('name')

            $.ajax({
                type: "POST",
                url: "{% url 'like' %}",
                data: { 'pk': pk, 'csrfmiddlewaretoken': '{{ csrf_token }}' },
                dataType: "json",

                success: function (response) {
                    if (response.likes_count == 1) {
                        $('#count' + pk).html(response.likes_count + ' like ');
                        $('#like-img' + pk).attr('src', '/static/like_after.png');
                    } else if (response.likes_count == 0) {
                        $('#count' + pk).html('0 like');
                        $('#like-img' + pk).attr('src', '/static/like_before.png');
                    } else {
                        $('#count' + pk).html(response.likes_count + ' like');
                        $('#like-img' + pk).attr('src', '/static/like_after.png');
                    }
                    alert(response.message);
                },
                error: function (request, status, error) {
                    alert('로그인이 필요합니다.')
                }
            });
        })

        $(".comment_writer_name")
        $(".comment_writer_name")[0].innerHTML

        for (i = 0; i < $(".comment_writer_name").length; i++) {
            if ($("#user_name").text() == $(".comment_writer_name")[i].innerHTML) {
                $("#control_id1" + i).removeClass("hidden");
            }
        }

    </script>

</body>
{% endblock %}

마무리