Django 포스팅 좋아요 기능 구현하기

2022. 2. 22. 22:44강의 정리/Django 기초

반응형

출처 : https://www.inflearn.com/course/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%9E%A5%EA%B3%A0-%EC%9B%B9%EC%84%9C%EB%B9%84%EC%8A%A4/dashboard

 

장고(Django)를 배우기 시작한 입문자이시거나, 또는 배우고 싶은 생각이 있으신 분은 위 출처의 강의를 적극 추천드립니다!!!

 


 

Django 포스팅 좋아요 / 취소 구현하기

#insta/models.py

class Post(BaseModel):
    author = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="my_post_set", on_delete=models.CASCADE)
    # 중략
    like_user_set = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="like_post_set", blank=True)

 

_필드의 related_name 옵션을 설정해주면, 쿼리셋시에 related_name을 이용하여 모델 객체를 불러올 수 있습니다.

ex) 

기존 -> Post.objects.filter(author=user) 

related_name -> user.my_post_set.all()     

 

 

_related_name 이란

참조되는 테이블이 참조하는 테이블의 데이터를 가져오고 싶을 때 사용하는 이름을 정의하는 것입니다,

 

 

_ManyToManyField 란??

https://velog.io/@jiffydev/Django-9.-ManyToManyField-1

 

Django 9. ManyToManyField 1

1. Many-to-Many relationship 데이터베이스의 Many-to-Many relationship(이하 다대다 관계)는 처음 접하는 사람들을 힘들게 한다. 한 테이블의 여러 레코드가 다른 테이블의 여러 레코드와 연결되어 있는 관계

velog.io

 

 

_user.my_post_set은 유저가 작성한 포스팅에 접근하게 되고, user.like_post_set은 유저가 좋아요를 누른 포스팅에 접근하게 됩니다.

 

 


 

#insta/urls.py

urlpatterns = [    
    path('post/<int:pk>/like', views.post_like, name='post_like'),
    path('post/<int:pk>/unlike', views.post_unlike, name='post_unlike'),
    ]

 

_ post_detail에 맞게 즉 포스팅 디테일뷰가 보여지는 url과 똑같이 매핑합니다.

 


#insta/views.py

# 포스팅 좋아요
@login_required
def post_like(request, pk):
    post = get_object_or_404(Post, pk=pk)
    
    post.user_like_set.add(request.user)
    
    messages.success(request, f"{post}를 좋아합니다.")
    
    redirect_url = request.META.get("HTTP_REFERER", "root") # HTTP_REFERER은 request 요청을 한 웹페이지의 주소를 보여준다.
    # 만약 HTTP_REFERER가 없으면 root 주소를 가져온다.
    return redirect(redirect_url)


# 포스팅 싫어요
@login_required
def post_unlike(request, pk):
    post = get_object_or_404(Post, pk=pk)
    
	post.user_like_set.remove(request.user)


	messages.success(request, f"{post}를 좋아요를 취소합니다.")
    
    redirect_url = request.META.get("HTTP_REFERER", "root") # HTTP_REFERER은 request 요청을 한 웹페이지의 주소를 보여준다.
    # 만약 HTTP_REFERER가 없으면 root 주소를 가져온다.
    return redirect(redirect_url)

 

_ request.META.get()이란??

request.META는 사용자의 IP 주소와 사용자 Agent(일반적으로 웹 브라우저의 이름과 버전)를 포함해 지정된 요청에 대해 사용할 수 있는 모든 HTTP 헤더가 들어있는 파이썬 딕셔너리 입니다.

출처 : https://yonghyunlee.gitlab.io/python/django-master-6/

 

 


템플릿단

#insta/templates/insta/_post_card.html

{% load bootstrap4 %}
{% load insta_tags %}


<div class="card">
    <div class="card-header">    
        <img src= "{{ user.profile_url }}" style="width: 24px; height: 24px;"/>
        <a href="{% url "insta:user_page" post.author.username %}" style="text-decoration:none">
            {{ post.author }}    
        </a>                
    </div>
    <div class="card-body">   
        {% if post.photo.url %}
            <img src="{{ post.photo.url  }}" style="width: 100%;"/>
        {% endif %}  
        {% for tag in post.tag_set.all %}
            <span class="badge badge-primary" style="color: #fff;
            background-color: #007bff;">                        
                #{{ tag.name }}
            </span>
        {% endfor %}                         
    </div>
    <div class="card-footer">                           
        
        {% if post|is_like_user:user %}
            <a href="{% url 'insta:post_unlike' post.pk %}" style="text-decoration:none">
                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#FF0000" class="bi bi-heart-fill" viewBox="0 0 16 16">
                    <path fill-rule="evenodd" d="M8 1.314C12.438-3.248 23.534 4.735 8 15-7.534 4.736 3.562-3.248 8 1.314z"/>
                </svg>
            </a>
        {% else %}
            <a href="{% url 'insta:post_like' post.pk %}" style="text-decoration:none">
                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#FF0000" class="bi bi-heart" viewBox="0 0 16 16">
                    <path d="m8 2.748-.717-.737C5.6.281 2.514.878 1.4 3.053c-.523 1.023-.641 2.5.314 4.385.92 1.815 2.834 3.989 6.286 6.357 3.452-2.368 5.365-4.542 6.286-6.357.955-1.886.838-3.362.314-4.385C13.486.878 10.4.28 8.717 2.01L8 2.748zM8 15C-7.333 4.868 3.279-3.04 7.824 1.143c.06.055.119.112.176.171a3.12 3.12 0 0 1 .176-.17C12.72-3.042 23.333 4.867 8 15z"/>
                </svg> 
            </a>
        {% endif %}
    </div>
</div>

 

 

 

 

{{ post|is_like_user:user }}

_ Pipe(='|') 앞의 인자"post"는 tags.py 함수의 첫번째 인자로 넘어가고, "user"은 두번째 인자로 넘어갑니다.

 

아래 코드는 위 이해를 돕기위한 tags.py의 함수입니다.

@register.filter
def is_like_user(post, user):
    # 해당 글의 is_like_user를 반환 하여줍니다.
    return post.is_like_user(user)

 

_위 tags.py 함수는 모델단의 함수를 호출시켜줍니다.

    # 만약 유저가 포스팅을 좋아한다면(=like_user_set에 유저 pk가 있다면) True를 반환
    def is_like_user(self, user):
        return self.like_user_set.filter(pk=user.pk).exists()

 

템플릿에서 -> tags.py 함수 호출 -> tags.py에서 model단 함수 호출

 

 

_ 아이콘을 지원해주는 사이트들

https://icons.getbootstrap.kr/

 

Bootstrap Icons

Bootstrap을 위한 공식 오픈 소스 SVG 아이콘 라이브러리

icons.getbootstrap.kr

https://fontawesome.com/icons

 

Font Awesome

The world’s most popular and easiest to use icon set just got an upgrade. More icons. More styles. More Options.

fontawesome.com

 


 

_장고 템플릿 단에서 함수를 호출하고, 인자를 넘기고 싶다면 Django custom templates filter를

적용해야합니다.

https://docs.djangoproject.com/ko/4.0/howto/custom-template-tags/

 

How to create custom template tags and filters | Django 문서 | Django

Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate

docs.djangoproject.com

 

0. 해당 앱에 templatestags 라는 폴더를 만들어줍니다.

 

1. templatestags 폴더 안에 '__init__.py'와 'app이름_tags.py'를 만들어줍니다.

 

 

#insta/templatetags/insta_tags.py

from django import template

register = template.Library()


@register.filter
def is_like_user(post, user):
    # 해당 글의 is_like_user를 반환 하여줍니다.
    return post.is_like_user(user)

 

반응형