[django] 관계를 표현하는 모델 필드
RDBMS에서의 관계 예시
- 1 : N 관계 -> models.ForeignKey로 표현
- 1명의 유저(User)가 쓰는 다수의 포스팅(Post)
- 1명의 유저(User)가 쓰는 다수의 댓글(Comment)
- 1개의 포스팅(Post)에 다수의 댓글(Comment)
- N 측에 외래키를 심는다!!
- 1 : 1 관계 -> models.OneToOneField로 표현
- 1명의 유저(User)는 1개의 프로필(Profile)
- 둘다 되지만 profile측에 onetoonefield로 지정한다.
- 1명의 유저(User)는 1개의 프로필(Profile)
- M : N 관계 -> models.ManyToManyField로 표현
- 1개의 포스팅(Post)에는 다수의 태그(Tag)
- 1개의 태그(Tag)에는 다수의 포스팅(Post)
- 1개의 포스팅(Post)에는 다수의 태그(Tag)
ForeignKey
- 1 : N 관계에서 N측에 명시
- ex) Post:Comment, User:Post, User:Comment,
-
ForeignKey(to, on_delete)
- 예시) models.ForeignKey(Post, on_delete=models.CASCADE)
- to : 대상모델
- 클래스를 직접 지정하거나,
- 클래스명을 문자열로 지정. 자기 참조는 “self” 지정
- on_delete : Record 삭제 시 Rule à
- CASCADE : FK(외래키)로 참조하는 다른 모델의 Record도 삭제 (장고 1.X에서의 디폴트값)
- PROTECT : ProtectedError (IntegrityError 상속) 를 발생시키며, 삭제 방지
- SET_NULL : null로 대체. 필드에 null=True 옵션 필수.
- SET_DEFAULT : 디폴트 값으로 대체. 필드에 디폴트값 지정 필수.
- SET : 대체할 값이나 함수 지정. 함수의 경우 호출하여 리턴값을 사용.
- DO_NOTHING : 어떠한 액션 X. DB에 따라 오류가 발생할 수도 있습니다
- 외래키로 참조를 한다면?
class Comment(mdels.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
message = models.TextField()
...
- 이러면 post_id 필드가 생성이 된다.
-
Post의 pk값을 통해 참조를 하는것이여서 post_id 필드가 생성이 되어 post_id로 접근을 해서 Post 모델에 참조한다.
- user 모델을 쓸 때 프로젝트 만들자마자 settings로 가서
- AUTH_USER_MODEL = “유저 모델을 쓸 앱이름.User” 쓰기!!
- 안쓰면 default 값이 “auth.User”이다.
-
그래서 User 모델을 대상모델로 지정하고 싶다면??
- models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
- comment에서 post 접근
- 즉 N에서 1로 접근
- Post에서 Comment 접근
- 즉 1에서 N으로 접근
OneToOneField
- 1 : 1 관계에서 어느 쪽이라도 가능
- User:Profile
- ForeignKey(unique=True)와 유사하지만, reverse 차이
- User:Profile를 FK로 지정한다면 -> profile.user_set.first() -> user
- User:Profile를 OneToOne 필드로 지정한다면 -> profile.user -> user
- OneToOneField(to, on_delete)
python # django/contrib/auth/models.py class User(AbstractBaseUser): ... # accounts/models.py class Profile(models.Model): author = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
https://docs.djangoproject.com/en/3.0/ref/models/fields/#onetoonefield
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)
- 이 필드를 만들게 된다면 중간 모델이 생성되게 됨
- 예를 들어 post와 tag가 manytomany 관계여서 한쪽에 이 필드를 만들었다면?
- 앱이름_post_tag_set 이라는 모델이 생성됨
쉘에서 태그 추가, 제거 방법
- tag = Tag.objects.get(name=”장고”)
- post.tag_set.add(tag) // 생성
- post.tag_set.remove(tag) // 제거
- 하나만 집어넣는것이 가능한데 여러개를 한번에 추가하고 싶다면??
- 여러개가 담겨 있는 변수에 *를 붙여주면됨
- ex)
- tag_qs = Tag.objects.all()
- post.tag_set.add(*tag_qs)
https://docs.djangoproject.com/en/2.1/ref/models/fields/#manytomanyfield
RDBMS지만, DB따라 NoSQL기능도 지원
- ex) 하나의 Post 안에 다수의 댓글 저장 가능
- djkoch/jsonfield
- 대개의 DB엔진에서 사용 가능
- TextField/CharField를 래핑
- dict 등의 타입에 대한 저장을 직렬화하여 문자열로 저장
- 내부 필드에 대해 쿼리 불가
- django.contrib.postgres.fields.JSONField
- 내부적으로 PostgreSQL의 jsonb 타입
- 내부 필드에 대해 쿼리 지원
- 예시
- posts = models.JSONField(default=’{}’)
- adamchainz/django-mysql
- MySQL 5.7 이상에서 json 필드 지원
댓글남기기