bestwish
Hong's Tistory
bestwish
전체 방문자
오늘
어제
  • 분류 전체보기 (32)
    • DevOps (21)
      • Django (15)
      • TIL (2)
      • Python (2)
      • Git (0)
      • Docker (1)
      • Infra (1)
    • Algorithm (3)
      • 백준문제 (3)
      • 이론 (0)
    • CS (6)
      • Data Structure (6)

인기 글

최근 글

hELLO · Designed By 정상우.
bestwish

Hong's Tistory

DevOps/Django

[Django] ForeignKey

2022. 5. 17. 02:33

1:N 관계

  • models.ForeignKey로 표현한다.
  • N측에 명시한다. (Post : Comment이면, Comment에 명시)
  • ForeignKey(to, on_delete)
    • to : 대상모델
      • 클래스를 직접 지정하거나, 클래스명을 문자열로 지정한다. (자기 참조는 self)
    • on_delete : Record 삭제시 규칙
      • CASCADE : FK로 참조하는 다른 모델의 Record도 삭제
      • PROJECT : ProtectedError (IntegrityError 상속)을 발생시키며, 삭제 방지
      • SET_NULL : Record가 삭제되었을시 null로 대체한다. 필드에 null=True 옵션 필수.
      • SET_DEFAULT : 디폴트 값으로 대체한다. 필드에 디폴트 값 지정 필수.
      • SET : 대체할 값이나 함수 지정. 함수의 경우 호출하여 리턴값을 사용.
      • DO_NOTHING : 어떠한 액션 X, DB에 따라 오류가 발생할 수 있다.
# <app>/models.py
class Post(models.Model):
    message = models.TextField()
    photo = models.ImageField(blank=True, upload_to='instagram/post/%Y/%m/%d')
    is_public = models.BooleanField(default=False, verbose_name='공개여부')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.message


class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    # post = models.ForeignKey('instagram.Post', on_delete=models.CASCADE) 
    # 문자열을 이용하여 다른 앱을 import 하지 않고 사용 가능하다.
    message = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True) 

 

FK에서의 reverse_name

  • reverse 접근 시의 속성명 : 디폴트 ➨ 모델명소문자_set
  • 1:N 관계에서 1측에서 사용한다. (1측에서는 N에 참조할 값이 없기때문에)
post = Post.objects.first() # <Post: 세번째 글>

# 아래 4개의 결과는 모두 같다.
Comment.objects.filter(post_id=4) # post_id는 직접적인 field를 말한다.
Comment.objects.filter(post__id=4) # 관계에 있는(Post 측에 있는 id를 가져온다.)
Comment.objects.filter(post=post)

post.comment_set.all()

# <QuerySet [<Comment: Comment object (1)>]>

 

reverse_name 이름이 충돌이 발생하면?

  • reverse_name 디폴트 명은 앱이름을 고려하지않는다. 모델명만 고려
  • 예시
    • blog앱 Post모델, author = FK(User)
    • shop앱 Post모델, author = FK(User)
  • 해결방법
    1. 어느 한 쪽의 FK에 대해, reverse_name을 포기 ➨ related_name='+'
    2. 어느 한 쪽(혹은 모두)의 FK의 reverse_name을 변경
      • FK(User, …, related_name='blog_post_set')
      • FK(User, …, related_name='shop_post_set')

 

ForeignKey.limit_choices_to 옵션

  • Form을 통한 Choice 위젯에서 선택항목 제한 가능.
    • dict/Q 객체를 통한 지정 : 일괄 지정
    • dict/Q 객체를 리턴하는 함수 지정 : 매번 다른 조건 지정 가능
  • ManyTOManyField에서도 지원
    • post = models.ForeignKey(Post, on_delete=models.CASCADE, limit_choices_to={'is_public': True})처럼 사용 가능하다.

 

1:1 관계

  • models.OneToOneField로 표현한다.
  • 1:1 관계 어느 쪽이든 명시 가능하다.
  • ForeginKey(unique=True)와 유사하지만, revere차이가 있다.
    • User:Profile을 1:N 관계로 지정하면, profile.user코드와 user.profile_set.all()코드를 쓸 수 있다.
    • User.Profile을 1:1 관계로 지정하면, profile.user코드와 user.profile 코드를 쓸 수 있다.
      user.profile 시에 user와 관계에 있는 Profile이 없는 경우, Profile.DoesNotExist 예외가 발생한다.
# django/contrib/auth/models.py
class User(AbstractBaseUser):
    ...


# <app>/models.py
class Profile(models.Model):
    author = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

 

M:N 관계

  • models.ManyToManyField로 표현한다.
  • M:N 관계 어느 쪽이든 명시 가능하다.
  • ManyToManyField(to, blank=False)
# 방법 1
class Post(models.Model):
    tag_set = models.ManyToManyField('Tag', blank=True)


class Article(models.Model):
    tag_set = models.ManyToManyField('Tag', blank=True)


class Tag(models.Model):
    name = models.CharField(max_length=100, unique=True)

# 방법 2
class Post(models.Model):
    ...


class Article(models.Model):
    ...


class Tag(models.Model):
    name = models.CharField(max_length=100, unique=True)
    post_set = models.ManyToManyField('Post', blank=True)
    article_set = models.ManyToManyField('Article', blank=True)

'DevOps > Django' 카테고리의 다른 글

[Django] SENDGRID를 이용한 메일 보내기.  (0) 2022.11.10
[Django] HTTP 상태코드 응답  (0) 2022.05.24
[Django] django-debug-toolbar 사용하기  (0) 2022.05.16
[Django] django extensions shell_plus 사용하기  (0) 2022.05.16
[Django] 장고 모델(ORM)  (0) 2022.05.11
    'DevOps/Django' 카테고리의 다른 글
    • [Django] SENDGRID를 이용한 메일 보내기.
    • [Django] HTTP 상태코드 응답
    • [Django] django-debug-toolbar 사용하기
    • [Django] django extensions shell_plus 사용하기
    bestwish
    bestwish

    티스토리툴바