1:N 관계 (Many-to-One Relationships)
한 개의 객체가 여러 개의 다른 객체와 연결
- Article(게시글) - Comment (댓글)
하나의 Article은 여러 개의 Comment를 가질 수 있음
하나의 Comment는 하나의 Article에 속함 - Author(작성자) - Article (게시글)
하나의 Author는 여러 개의 Article을 가질 수 있음
하나의 Article은 하나의 Author만 가질 수 있음
*ForeignKey (외래키)
다른 모델을 참조하는 필드
→ 관계형 데이터베이스에서 한 테이블의 필드 중 다른 테이블의 행을 유일하게 식별 가능한 키
→ 테이블에 설정되는 Foreign Key가 반드시 다른 테이블의 Primary Key일 필요는 없으나 유일하게 식별이 가능해야 함
models.ForeignKey(참조할 모델 클래스, on_delete=옵션)
*on_delete 옵션
- CASCADE : 부모 객체가 삭제되면 자식 객체도 삭제됨
- PROTECT : 자식 객체가 존재하면 부모 삭제 불가 (예외 발생)
- SET_NULL : 부모 객체가 삭제되면 자식 객체의 해당 필드가 NULL이 됨
댓글(Comment) 모델 구현
1:N 관계 설정 - articles/models.py
- article = models.ForeignKey(Article, on_delete=models.CASCADE)
- author = models.ForeignKey(User, on_delete=models.CASCADE)
- 댓글(Comment)이 Article을 참조하는 외래키(ForeignKey) 추가
- 댓글이 User를 참조하는 외래키(ForeignKey) 추가
- on_delete=models.CASCADE 옵션을 사용, Article 또는 Author가 삭제되면 관련 Comment도 삭제됨
ORM을 활용한 데이터 조작
Django Shell에서 ORM 사용
python manage.py shell_plus
댓글(Comment) 생성
article = Article.objects.first() # 첫 번째 게시글 가져오기
comment = Comment()
comment.article = article # ForeignKey 지정
comment.content = "첫 번째 댓글"
comment.save()
댓글에서 게시글(Article) 접근 (정참조)
comment.article.title # 댓글이 속한 게시글의 제목 출력
게시글에서 모든 댓글 가져오기 (역참조)
article.comments.all() # 해당 게시글의 모든 댓글 조회
Django는 역참조(Related Manager) 를 자동으로 생성
기본적으로
모델이름_set
(article.comment_set.all())
이지만,
related_name="comments" 옵션을 ForeignKey에 추가하면 article.comments.all()처럼 변경 가능
댓글 입력 및 저장 (Form 사용)
forms.py (1차) - 모든 필드 포함
from django import forms
from .models import Comment
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = "__all__" # 모든 필드 포함
사용자가 article을 직접 선택해야 함 → 보안상 문제 발생 가능
forms.py (2차) - article, author 제외
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = "__all__"
exclude = ("article","author") # 사용자가 직접 article, author을 지정하지 못하도록 제외
댓글 생성 및 저장 (View 설정)
articles/views.py - 댓글 저장 로직
- commit=False: DB에 즉시 저장하지 않고, 객체만 생성하여 추가적인 데이터 설정 가능
댓글 입력 폼 및 목록 표시 (Template 설정)
article_detail.html - 댓글 입력 폼
<hr>
<h3>댓글</h3>
<form action="{% url 'articles:comment_create' article.pk %}" method="POST">
{% csrf_token %}
{{ comment_form.as_p }}
<input type="submit" value="댓글작성">
</form>
article_detail.html - 댓글 목록 표시
<ul>
{% for comment in comments %}
<li>
<p>{{ comment.content }}</p>
</li>
{% endfor %}
</ul>
또는 역참조를 활용하여 view 수정 없이 바로 해결 가능
<ul>
{% for comment in article.comments.all %}
<li>
<p>{{ comment.content }}</p>
</li>
{% endfor %}
</ul>
댓글 삭제 기능 추가
articles/urls.py - 댓글 삭제 URL 추가
path("comments/<int:comment_pk>/delete/", views.comment_delete, name="comment_delete"),
articles/views.py - 댓글 삭제 뷰 추가
@require_POST
def comment_delete(request, comment_pk):
comment = get_object_or_404(Comment, pk=comment_pk)
article_pk = comment.article.pk # 삭제 후 리다이렉트할 게시글의 PK 저장
comment.delete()
return redirect("articles:article_detail", article_pk)
article_detail.html - 댓글 삭제 버튼 추가
<ul>
{% for comment in comments %}
<li>
<p>{{ comment.content }}</p>
<form action="{% url 'articles:comment_delete' comment.pk %}" method="POST" style="display:inline;">
{% csrf_token %}
<input type="submit" value="삭제">
</form>
</li>
{% endfor %}
</ul>
전체 댓글 개수 표시
article_detail.html - 댓글 개수 출력
<h3>댓글 ({{ comments.count }})</h3>
최종 article_detail.html 코드
1:N 관계는 ForeignKey를 사용하여 설정
ORM을 사용하여 데이터 조작 가능 (article.comments.all() 활용)
save(commit=False)를 사용하여 추가 로직 처리 후 저장
댓글 CRUD 기능 구현 (생성, 조회, 삭제)
템플릿에서 역참조 (article.comments.all())를 사용하여 데이터 표시 가능
'∟ Framework > ⊢ Django' 카테고리의 다른 글
Django - Model Relationship (M:N) (0) | 2025.02.24 |
---|---|
Django - Custom User Model (0) | 2025.02.24 |
Django - Admin Site 활용 (1) | 2025.02.13 |
Django - Static & Media (2) | 2025.02.08 |
Django - 회원기능 구현하기 (1) | 2025.02.06 |