코딩/Django

[Django] 역참조 테이블 필드로 정렬하기 (order_by)

작은코딩 2022. 3. 19. 20:11

피드 모델을 작성 시간(최신순)으로 정렬하는 방법은 created_at 필드를 이용하거나 id 필드를 이용하는 방법이 있다.

(id는 점점 커지는 특성이 있다.)

from feed.models import Feed

Feed.objects.order_by("-created_at")

Feed.objects.order_by("-id")

 

기본적인 정렬은 이렇게 쉽게 구현할 수 있지만 기능을 점점 확장시키다 보면 좀 더 다양한 방법으로 정렬을 할 필요성이 생긴다. 

 

이번 green_door프로젝트를 진행하면서 내가 생각한 문제와 그 해결법을 정리해보겠다.

 

내가 북마크한 피드를 마이페이지에서 보여줘야 하는데 어떤 기준으로 정렬시켜서 보여줘야 할까? 

 

가장 간단한건 일반 피드와 마찬가지로 최신순으로 정렬하는 거지만 내가 옛날 게시물을 북마크 했는데 그게 맨 뒤에 있다면 불편함을 느낄 거 같았다. 그래서 북마크 한 순서대로 정렬을 해보기로 하고 기능을 구현해봤다. 

 

 

greendoor.models.py

from django.db import models

# Create your models here.


class BaseModel(models.Model):
    updated_at = models.DateTimeField(auto_now=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        abstract = True

 

feed.models.py

from typing import Any, List

from django.db import models

from greendoor.models import BaseModel
from user.models import Users


class Feed(BaseModel):
    user_id = models.ForeignKey(Users, on_delete=models.CASCADE, related_name="feed", db_column="user_id")
    title = models.CharField(max_length=100)
    image = models.CharField(max_length=256)
    content = models.CharField(max_length=500, blank=True, null=True)
    like_count = models.IntegerField(default=0)

    my_likes: List[Any]  # Prefetch 에서 사용용
    my_bookmark: List[Any]  # Prefetch 에서 사용용
    

class FeedBookmark(BaseModel):
    user_id = models.ForeignKey(Users, on_delete=models.CASCADE, related_name="feed_bookmark", db_column="user_id")
    feed_id = models.ForeignKey(Feed, on_delete=models.CASCADE, related_name="feed_bookmark", db_column="feed_id")

    class Meta:
        constraints = [
            models.UniqueConstraint(fields=["user_id", "feed_id"], name="unique_user_feedbookmark"),
        ]

 

feed.services.feed_service.py

# 내 피드 조회 함수
def get_my_feed_list(user_id: int) -> QuerySet[Feed]:
    return (
        Feed.objects.order_by("-created_at")
        .prefetch_related(
            Prefetch(
                "feed_like",
                queryset=FeedLike.objects.filter(user_id=user_id),
                to_attr="my_likes",
            ),
            Prefetch(
                "feed_bookmark",
                queryset=FeedBookmark.objects.filter(user_id=user_id),
                to_attr="my_bookmark",
            ),
        )
        .filter(user_id=user_id)
    )


# 내가 북마크한 피드 조회 함수
def get_my_bookmark_feed_list(user_id: int) -> QuerySet[Feed]:
    return (
        Feed.objects
        .prefetch_related(
            Prefetch(
                "feed_like",
                queryset=FeedLike.objects.filter(user_id=user_id),
                to_attr="my_likes",
            ),
            Prefetch(
                "feed_bookmark",
                queryset=FeedBookmark.objects.filter(user_id=user_id),
                to_attr="my_bookmark",
            ),
        )
        .filter(feed_bookmark__user_id=user_id) # 역참조 관계에 있는 필드를 가져오려면 언더바 2개 사용
        .order_by("-feed_bookmark__created_at") # 역참조 관계에 있는 북마크 테이블의 최근 생성 순으로 정렬
    )

 

처음엔 많이 해멨는데 related_name을 쓰고 __(언더바 2개)를 사용하면 역참조 된 모델의 필드도 사용할 수 있다는 걸 알고 나선 쉽게 구현이 되었다. annotate를 사용해서 현재 모델의 필드로 재정의(?)를 해도 되지만 북마크 모델의 created_at 필드는 조회 말고는 따로 사용할 필요가 없어서 바로 참조를 했다.

'코딩 > Django' 카테고리의 다른 글

[Django] F( )표현식  (0) 2022.04.26
Django channels 실시간 채팅 기능 (websocket)  (3) 2022.03.06