1:N (Article - Comment)

Hvvany·2022년 10월 25일
0

django

목록 보기
8/10

RDB 복습

RDB

  • 데이터를 테이블, 행, 열 등으로 나누어 구조화하는 방식
  • 기본키 존재, 외래 키 사용하여 다른 테이블 간의 관계를 만들 수 있다.

테이블 간 관계 예시

주문 서비스 데이터베이스 : 고객 테이블, 주문 테이블

  • 고객 테이블 : 고객 정보
  • 주문 테이블 : 주문 정보
주문id고객id
제품명이름
주문일주소지
배송일배송지
주문상태

고객 정보 이름 저장

이렇게 저장하면 동명 이인 구분 불가능

주문id제품명주문일배송일주문상태고객정보
1생수2000-01-012000-01-01배송중김진수
2영양제2000-01-012000-01-01배송 준비중박영희
3음료수2000-01-012000-01-01배송중김진수

고객 정보 id 저장

이렇게 저장하면 동명 이인 구분 가능

주문id제품명주문일배송일주문상태고객정보
1생수2000-01-012000-01-01배송중2
2영양제2000-01-012000-01-01배송 준비중1
3음료수2000-01-012000-01-01배송중2


Foreign Key

개념

관계형 데이터베이스에서 다른 테이블의 행을 식별할 수 있는 키
참조되는 테이블의 기본 키를 가리킴

특징

키를 사용하여 부모 테이블의 유일한 값을 참조



1:N ( Article - Comment )

모델 관계 설정

게시글 : n개의 댓글을 가진다.
댓글 : 1개의 게시글에 속한다.

Django Relationship Fiedls 종류

  • OneToOneField()
    A one-to-one relationship
  • ForeignKey()
    A one-to-many relationship
  • ManyToManyField()
    A many-to-many relationship

Foreign Key ( to, on_delete, **options )

👉 Foreign Key 공식 문서

  • one-to-many ralationship을 담당하는 Django의 모델 필드 클래스
  • 2개의 필수 위치 인자가 필요
    • 참조하는 model class
    • on_delete 옵션

Foreign Key arguments - on_delete

👉 Foreign Key _ arguments 공식 문서

CASCADE

부모 객체가 삭제되었을 때 이를 참조하는 객체도 삭제

PROTECT

Prevent deletion of the referenced object by raising ProtectedError, a subclass of django.db.IntegrityError.

RESTRICT

Prevent deletion of the referenced object by raising RestrictedError (a subclass of django.db.IntegrityError). Unlike PROTECT, deletion of the referenced object is allowed if it also references a different object that is being deleted in the same operation, but via a CASCADE relationship.

등 다양함

Comment 모델 정의

models.py

정의 순서로 인한 ForeignKey argument 에러 주의

👉 공식문서 참고

1. Article 먼저 클래스 정의 된 경우

ForeignKey argument에 Article을 객체로 그냥 사용해도 오류가 없다.

class Article(models.Model):
    ...

class Comment(models.Model):
    ...
    article = models.ForeignKey(Article, on_delete=models.CASCADE)
2. Article 정의 전에 사용할 경우

Article 객체 대신 'Article' 문자열로 사용하면 된다.

class Comment(models.Model):
    ...
    article = models.ForeignKey('Article', on_delete=models.CASCADE)
    
class Article(models.Model):
    ...

articles/models.py

from django.db import models
from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFill

# Create your models here.
class Article(models.Model):
    ...

class Comment(models.Model):
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add = True)
    article = models.ForeignKey('Article', on_delete=models.CASCADE)

articles/admin.py

# admin에서 확인 위해 admin항목에 Comment를 추가해준다.

from django.contrib import admin
from .models import Article, Comment

# Register your models here.
class ArticleAdmin(admin.ModelAdmin):
  list_display = ('title','created_at','updated_at')

class CommentAdmin(admin.ModelAdmin):
  list_display = ('content','created_at','article')

admin.site.register(Article, ArticleAdmin)
admin.site.register(Comment,CommentAdmin)

직접 참조 역참조 객체 구분 적는 순서로 파악 가능

댓글 게시글 상세 페이지에 띄우기

article/views.py

...
def detail(request, pk):
  article = Article.objects.get(pk=pk)
  comments = article.comment_set.all()
  context={
    'article':article,
    'comments':comments
  }
  return render(request,'articles/detail.html', context)
...

detail.html

  {% for comment in comments %}
  <p>{{ comment.content }}</p>
  {% endfor %}

댓글이 없는 경우 대체 문자 띄우기

1. if 문으로 구현

  {% if comments %}
    {% for comment in comments %}
    <p>{{ comment.content }}</p>
    {% endfor %}
  {% else %}
    <p>댓글이 없습니다.</p>
  {% endif %}

2. empty 장고 템플릿 사용

    {% for comment in comments %}
    <p>{{ comment.content }}</p>
    {% empty %}
      <p>댓글이 없습니다.</p>
    {% endfor %}

댓글 작성 폼 추가하기

forms.py

from .models import Article, Comment

...
class CommentForm(forms.ModelForm):
  class Meta:
    model = Comment
    fields = ['content']
...

views.py

from .forms import ArticleForm, CommentForm

def detail(request, pk):
  ...
  comment_form = CommentForm
  context={
    ...
    'comment_form':comment_form,
  }
  return render(request,'articles/detail.html', context)

detail.html

	...
    <h2>댓글</h2>
    <form action="">
      {% bootstrap_form comment_form %}
      {% bootstrap_button button_type='submit' content='OK' %}
    </form>
    <hr>
	...

form을 저장하기 위한 작업

urls.py

	path('<int:pk>/comments/', views.comment_create, name='comment_create'),

views.py

def comment_create(request, pk):
  article = Article.objects.get(pk=pk)
  comment_form = CommentForm(request.POST)
  if comment_form.is_valid():
    comment_form.save()
  return redirect('articles:detail', article.pk)

detail.html

...
<h2>댓글</h2>
    <form action="{% url 'articles:comment_create' article.pk %}" method='POST'>
      {% csrf_token %}
      {% bootstrap_form comment_form layout='inline' %}
      {% bootstrap_button button_type='submit' content='OK' %}
    </form>
...

에러가 뜬다
사용자가 입력하는 값 이 외에도 추가로 입력해주어야 하는 정보가 있어서 일단 저장을 멈추고 추가 정보를 넘겨준 후 저장하는 방법!!

views.py

def comment_create(request, pk):
  article = Article.objects.get(pk=pk)
  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)

CommentForm클래스의 인스턴스 comment_form
Comment 클래스의 인스턴스 comment
=> 모델폼의 save 메서드는 리턴 값이 그 모델의 인스턴스이다.

profile
Just Do It

0개의 댓글