1 minute read

매니저

[모델이름].objects.all() 에서 .objects를 매니저라고 한다.
매니저는 장고 모델과 데이터베이스를 연결해 주는 인터페이스이다.
매니저를 통해 모델에 대한 ORM 연산을 수행할 수 있고 베이스 또는 기본 쿼리셋이 숨어있다.

숨겨진 쿼리셋 안에는 모델에 해당하는 모든 오브젝트들이 있고 일반 쿼리셋처럼 사용할 수 없다.
for post in Post.objects:
이렇게 사용할 수 없고
for post in Post.objects.all():
이렇게 사용해야 한다.

그리고 매니저에 CRUD 연산을 하면 숨겨진 쿼리셋이 사용된다.
Post.objects.order_by()
이렇게 숨겨진 쿼리셋을 정렬해서 리턴해준다.
Post.obejcts.all().order_by()
그래서 이렇게 사용하지 않는다.

역관계

역관계는 관계를 정의하는 필드를 통해 연결된 오브젝트에 접근하는 것이다.

class Comment(models.Model):
    content = models.TextField(max_length=500, blank=False)
    author = models.ForeignKey(User, on_delete=models.CASCADE) 

User는 comment.author로 접근이 가능하다.
외래키는 한 쪽에만 작성을 하므로 외래키를 작성한 Comment에서만 접근이 가능할 것 같지만 반대로 User모델에서도 Comment모델로 접근이 가능한데
장고는 자동으로 반대 방향으로 접근할 수 있게 역관계를 만들어 주기 때문이다.
user.comment_set으로 접근할 수 있다.
여기서 user.comment_set는 매니저다.
이렇게 접근한 댓글(comment)은 모든 댓글을 가지는 것이 아니라 user가 작성한 댓글만 가지고 있다.

역관계가 가리키는 오브젝트가 하나일 때는 [모델이름]으로 접근하고
여러개 일 때는 [모델이름]_set 으로 접근한다.

역관계의 이름을 변경하려면 related_name=”변경할 이름” 옵션을 주면 된다.

역관계가 필요없다면 related_name=”+” 를 주면 된다.

OneToOneField

class User(AbstractUser):
    ...

class Profile(models.Model):
    user = models.OneToOneField(User, ...)

프로필을 가지고 있는 유저는 profile.user로 접근
유저의 프로필은 user.profile로 접근

여기서 user.profile은 매니저가 아닌 실제 오브젝트다.
그래서 user.profile.nickname 이런식으로 접근할 수 있다.

ManyToManyField

class User(AbstractUser):
    ...
    following = models.ManyToManyField('self', ...)

유저가 팔로우 하는 유저들 user.following
유저를 팔로우 하고 있는 유저들 user.user_set

이렇게 여러 오브젝트를 가리킬 때 user.following은 매니저이다.

GenericForeignKey

GenericForeignKey는 자동으로 역관계를 만들어 주지 않는다.

from django.contrib.contenttypes.fields import GenericRelation

class Review(models.Model):
    ...
    likes = GenericRelation('Like')
    ...

class Like(models.Model):
    ...
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)

    object_id = models.PositiveIntegerField()

    liked_object = GenericForeignKey()

GenericForeignKey에는 on_delete옵션을 사용할 수 없지만
제네릭 관계가 가리키는 모델에 GenericRelation필드를 추가하면 CASCADE같은 효과를 얻을 수 있다.

content_type과 object_id이름을 사용했기 때문에 역관계를 형성하는 모델 이름만 넘기면 된다. 다른 이름을 사용했다면 알려줘야 한다.

related_query_name

User.objects.filter(following__id=1)
이런식으로 필터를 할수 있다.

GenericForeignKey로는 필터를 할 수 없다.
다양한 종류의 오브젝트를 가리키기 때문에 어떤 종류의 오브젝트인지 알 수가 없다.
이럴 때는 related_query_name속성을 사용하면 된다.

class Comment(models.Model):
    likes = GenericRelation('Like', related_query_name='comment')

Like.objects.filter(comment=comment)
이렇게 특정 Comment에 속해있는 Like오브젝트를 필터할 수 있다.

검색기능

Q오브젝트

여러 필터 조건들을 or 한다.

조건들을 and하려면
Post.objects.filter(user=user).filter(post=post)
Post.objects.filter(user=user, post=post)
이렇게 하면 된다.

조건들을 or하려면 Q오브젝트를 사용해야 한다.
Q오브젝트는 어떤 조건을 저장하는 오브젝트를 말한다.

from django.db.models import Q

q1 = Q(field1=val1)
q2 = Q(field2=val2)

[모델].objects.filter(q1 | q2)
[모델].objects.filter(Q(field3=val3) | Q(field4=val4))

이렇게 or할 수 있다.

Leave a comment