Realtionships
- 한 테이블의 0개 이상의 레코드가 다른 테이블의 레코드 한 개와 관련된 관계
Comment - Article
- 0개 이상의 댓글은 1개의 게시글에 작성될 수 있다.
Comment(N) - Article(1)
- 0개 이상의 댓글은 1개의 게시글에 작성될 수 있다.
ForeignKey()
댓글 모델 정의
- ForiegnKey 클래스의 인스턴스 이름은 참조하는 모델 클래스 이름의 단수형으로 작성하는 것을 권장
- 외래 키는 ForiegnKey 클래스를 작성하는 위치와 관계없이 테이블 필드 마지막에 생성됨
class Comment(models.Model):
article = models.ForeignKey(Article, on_delete=models.CASCADE)
content = models.CharField(max_length=200)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
ForeignKey(to, on_delete)
- to : 참조하는 모델 class 이름
- on_delete : 외래 키가 참조하는 객체(1)가 사라졌을 때, 외래 키를 가진 객체(N)를 어떻게 처리할 지를 정의하는 설정(데이터 무결성)
- on_delete의 'CASCADE' : 부모 객체(참조 된 객체)가 삭제 됐을 때, 이를 참조하는 객체도 삭제
댓글 생성 연습
comment = Comment()
comment.content = 'first comment'
article = Article.objects.get(pk=1)
comment.article = article
comment.save()
comment = Comment(content='second comment', article=article)
comment.save()
역참조
- N:1 관계에서 1에서 N을 참조하거나 조회하는 것
- N은 외래 키를 가지고 있어 물리적으로 참조가 가능하지만 1은 N에 대한 참조방법이 존재하지 않아 별도의 역참조 기능이 필요
- article.comment_set.all()
- 모델.역참조 이름. QeurySet API
- 특정 게시글에 작성된 댓글 전체를 조회하는 명령
- N:1 혹은 M:N 관계에서 역참조 시에 사용하는 매니저
- 'objects' 매니저를 통해 QeurySet API를 사용했던 것처럼 related manager를 통해 QuerySet APU를 사용할 수 있게 됨
- shell_plus 연습
article = Article.objects.get(pk=1)
comments = article.comment_set.all()
for comment in comments:
print(comment.content)
댓글 구현
CREATE
from django import forms
from .models import Article, Comment
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = '__all__'
def detail(request, pk):
article = Article.objects.get(pk=pk)
comment_form = CommentForm()
context = {
'article': article,
'comment_form': comment_form,
}
return render(request, 'articles/detail.html', context)
def comments_create(request, pk):
article = Article.objects.get(pk=pk)
comments = article.comment_set.all()
comment_form = CommentForm(request.POST)
if comment_form.is_valid():
comment = comment_form.save(commit=False)
comment.article = article
comment.save()
return redirect('articles:detail', article.pk)
context = {
'comment_form': comment_form,
'article': article,
'comments': comments,
}
return render(request, 'articles/detail.html', context)
<form action="{% url "articles:comments_create" article.pk %}" method="POST">
{% csrf_token %}
{{ comment_form }}
<input type="submit" value="댓글 작성">
</form>
urlpatterns = [
path('<int:pk>/comments/', views.comments_create, name='comments_create'),
]
PS. NO Reverse Match 오류 발생시 -> 현재 URL 태그 확인
READ
def detail(request, pk):
article = Article.objects.get(pk=pk)
comments = article.comment_set.all()
comment_form = CommentForm()
context = {
'article': article,
'comments' : comments,
'comment_form': comment_form,
}
return render(request, 'articles/detail.html', context)
Delete
urlpatterns = [
path('<int:article_pk>/comments/<int:comment_pk>/delete/', views.comments_delete, name='comments_delete'),
]
def comments_delete(request, article_pk, comment_pk):
comment = Comment.objects.get(pk=comment_pk)
comment.delete()
return redirect('articles:detail', article_pk)
{% for comment in comments %}
<li>
{{ comment.content }}
<form action="{% url "articles:comments_delete" article.pk comment.pk %}" method="POST" style="display: inline;">
{% csrf_token %}
<input type="submit" value="삭제">
</form>
</li>
{% endfor %}