∟ Framework/⊢ Django

Django - 1:N 관계 (Many-to-One Relationships)

최 수빈 2025. 2. 20. 16:54

 

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

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 - 댓글 저장 로직

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 코드

articles/templates/articles/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