Django 댓글 구현하기

2022. 2. 23. 13:05강의 정리/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 BaseModel(models.Model):

    class Meta:
        # 아래 코드를 통해 실제 DB에 적용되지 않고, 추상 클래스로 만들어진다.
        abstract = True


class Comment(BaseModel):
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    message = models.TextField()

    class Meta:
        ordering = ['-id']

 

_ 항상 모델단에 ordering을 통해 정렬을 하는것을 추천합니다.

 

 

_ Django에서는 정수나 날짜등을 사람이 보기 보다 편하게 해주는 템플릿 필터가 존재합니다.

ex) 예를 들어 숫자에 컴마를 찍어준다거나, 날짜를 today, yesterday등으로 바꿔줍니다.

 

https://docs.djangoproject.com/en/4.0/ref/contrib/humanize/ 

 

django.contrib.humanize | Django documentation | Django

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

docs.djangoproject.com

 

_반드시 humanize를 INSTALLED_APPS에 먼저 추가 시켜주어야 합니다.

INSTALLED_APPS = [
    # Django Apps

    'django.contrib.humanize', # 추가

]

 


 

#insta/templates/insta/_post_card.html

 

{% load bootstrap4 humanize 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 %}  
        <div>
            {% 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 class="comment-list mt-3 mb-3">
            {% for comment in post.comment_set.all %}
            <div class="comment">
                <strong>{{ comment.author }}</strong>
                {{ comment.message }}
                <small class="text-muted">{{ comment.created_at|naturaltime }}</small>
            </div>
            {% endfor %}
        </div>

        <div>
            {% for tag in post.tag_set.all %}
                <span class="badge badge-primary" style="color: #fff;
                background-color: #007bff;">                        
                    #{{ tag.name }}
                </span>
            {% endfor %}  
        </div>         
        
        <div>
            <a href="{{ post.get_absolute_url }}" style="text-decoration:none" class="text-muted">
                <small>
                    {{ post.created_at|naturaltime }}
                </small>
            </a>
        </div>    
    </div>
    
    <div class="card-footer">                           
        <a href="{% url 'insta:comment_new' post.pk %}">
            댓글 쓰기
        </a>
    </div>
</div>

_반드시 템플릿 최상단에 humanize를 load 해주어야 오류가 안납니다!

 

 

 


 

#insta/forms.py

from django import forms
from .models import Post, Comment


class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields =  [
            'photo', 'caption', 'location'
        ]

        # 장고에서는 widgets 를 통해 특정 필드 위젯을 변경할 수 있다.
        widgets = {
            "caption" : forms.Textarea,
        }


class CommentForm(forms.ModelForm):
    class Meta:
        model = Comment
        fields = ["message"]

 

 

 

 

 


 

#insta/urls.py

urlpatterns = [

    # 아래 path에서는 comment가 주인공이기에 post_pk로 작성
    path('post/<int:post_pk>/comment/new/', views.comment_new, name='comment_new'),

    ]

 

 


 

#insta/views.py

# 댓글 쓰기
@login_required
def comment_new(request, post_pk):
    post = get_object_or_404(Post, pk=post_pk)

    if request.method == 'POST':
        form = CommentForm(request.POST, request.FILES)
        if form.is_valid():
            # 내부적으로 comment가 save되는 것을 막음 
            # 그 이유는 댓글 폼은 message 필드만 받기 때문에, 나머지 필드에서 오류가 생기기 때문이다.
            # 그러기에 나머지 필드를 채워준 상태에서 form을 저장 시켜야한다.
            comment = form.save(commit=False)
            comment.post = post
            comment.author = request.user
            comment.save()
            return redirect(comment.post)    
    else:
        form = CommentForm()
    return render(request, "insta/comment_form.html", {
        "form" : form,
    })

 

_ commit=False를 쓰는 이유는?

예를 들어서 필드가 4개가 있는 모델을 모델 폼으로 작성을 받을 때

나는 그 중 1개의 필드만 폼으로 작성하고 싶다!!

이 경우에 view 함수에서 유효성 검사 이후 form.save()를 먼저 하면 나머지 필드들은 값을 받지

못했으므로 오류가 발생합니다!

 

그러기에 우리는 장고에게 잠시만 저장을 미뤄줘~~! 라는 의미로 commit=False를 적어준 다음

나머지 필드들의 값을 지정해주는겁니다!

 

 


 

#insta/templates/insta/comment_form.html

{% extends "insta/layout.html" %}
{% load bootstrap4 %}

{% block content %}
    <div class="container">
        <div class="row">
            <div class="col-sm-6 offset-sm-3">
                {% include "_form.html" with form_title="새 댓글 쓰기" submit_label="새 댓글 쓰기"  %}
            </div>
        </div>
    </div>  
{% endblock %}

 

 

반응형

'강의 정리 > Django' 카테고리의 다른 글

동백 // Django admin을 통한 데이터 관리 (기초)  (0) 2021.12.27