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에 따라 오류가 발생할 수 있다.
- to : 대상모델
# <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)
- 해결방법
- 어느 한 쪽의 FK에 대해, reverse_name을 포기 ➨ related_name='+'
- 어느 한 쪽(혹은 모두)의 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 |