Skip to content

F()#

https://docs.djangoproject.com/en/4.2/ref/models/expressions/#f-expressions

F() 개체는 모델 필드의 값, 모델 필드의 변환된 값 또는 주석이 달린 열을 나타냅니다. 이를 통해 모델 필드 값을 참조하고 이를 사용하여 데이터베이스 작업을 수행할 수 있으므로 실제로 데이터베이스에서 파이썬 메모리로 가져올 필요 없이 데이터베이스 작업을 수행할 수 있습니다.

ORM을 사용할 때 파이썬이 아니라 DB 자체 쿼리를 사용하게 만들어주는 메서드.

Post.objects.annotate(title=F("post__comment")).values("title")

high performance#

벌크 업데이트를 수행할 때 파이썬으로 가져올 필요가 없으므로 성능이 높다.

Reporter.objects.update(stories_filed=F("stories_filed") + 1)

race conditions#

또, DB가 필드 값을 업데이트 하므로 race condition이 일어나지 않는다는 점도 장점이라고

returns PK rather than model instance#

Company.objects.annotate(built_by=F("manufacturer"))[0]

Q()#

AND(&), OR(|), NOT(~), XOR(^) 연산을 좀 더 편하게 만들어준다.

Poll.objects.get(
    Q(question__startswith="Who"),
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
)

사용사례

쿼리 파라메터로 필터링을 수행할때 어떤 옵션은 하나의 filter로 끝나지 않는 경우가 있었다. 예를 들어 메모들을 쿼리하는데 태그를 필터링하고자 할 경우, 필터링 하는 태그가 여러개일 수도 있다. 이 경우 반복문을 사용하여 filter를 해야 하는데, 이때 Q 객체를 쓰면 편하다.

class MemoListView(APIView):
    @extend_schema(
        summary="메모 조회",
        description="날짜와 다양한 분류,정렬 기준으로 사용자의 메모를 조회합니다.",
        parameters=[
            OpenApiParameter(
                name="tag[]",
                description="태그 필터. 태그 이름은 고유하기 때문에 tag_title을 사용합니다. 다중인자를 허용합니다.",
                required=False,
                type=str,
                many=True,
            ),
            ...
        ],
    )
    def get(self, request):
        user = request.user
        queryset = self.queryset.filter(memo_set__user_id=user.id)

        ...

        # `tag` filtering
        if param.get("tag[]"):
            tags = param.getlist("tag[]")
            q = Q()
            for tag_title in tags:
                q |= Q(memo_tags__title=tag_title)

            queryset = queryset.filter(q)

source code를 살펴보니 Q 오브젝트는 tree.Node를 상속받았다. 그 말은 즉슨 Q 오브젝트끼리 부모-자식 관계가 가능하다는 것이다. Node.create를 하고 새 Q 오브젝트를 add했다. 이때 Connector가 항상 따라붙는데, 간선에 OR, AND, XOR 연산을 정의하기 위해 사용하는 것 같다. 부울대수는 트리구조로 만들 수 있고, 그 정점끼리는 Q 오브젝트가 있으며, 간선은 정점간의 operator가 있는 셈이다.

예를 들어 A & ((B | (C ^ D)) & E) 를 트리구조로 표현하면 다음과 같이 될 것이다:

---
title: Boolean logic graph
---
graph LR
    A -- AND --- B
    B -- OR --- C
    B -- AND --- E
    C -- XOR --- D