본문 바로가기

개발일지/TIL

TIL 23-05-27 머신러닝 팀 프로젝트 - annotate()

1.머신러닝 팀 프로젝트 - annotate()

 문제점

모델이 가지고 있지 않은 ForeignKey 필드의 Count를 기준으로 정렬해야함 

class Article(models.Model):
    user = models.ForeignKey(
        User, verbose_name="작성자", on_delete=models.CASCADE, related_name="user_articles"
    )
    title = models.CharField("제목", max_length=30)
    content = models.TextField("내용", null=True)
    created_at = models.DateTimeField("작성시간", auto_now_add=True)
    updated_at = models.DateTimeField("수정시간", auto_now=True)
    like = models.ManyToManyField(
        User, verbose_name="좋아요", related_name="like_article", blank=True
    )

    def __str__(self):
        return str(self.title)

 

class HomeSerializer(serializers.ModelSerializer):
    like_count = serializers.SerializerMethodField()
    comments_count = serializers.SerializerMethodField()

    def get_like_count(self, obj):
        return obj.like.count()

    def get_comments_count(self, obj):
        return obj.comment_set.count()

    class Meta:
        model = Article
        fields = "__all__"

serializer로 field를 생성하고 그 값을 get_필드명으로 생성했지만, 정렬이 불가능

 

class HomeView(APIView):

    def get(self, request):
        articles = Article.objects.all()
        current_order = request.query_params.get("order_by")

        if current_order == "latest":
            articles = Article.objects.order_by("-created_at")
        elif current_order == "likes":
            articles = Article.objects.order_by("-like_count")
        elif current_order == "comments":
            articles = Article.objects.order_by("-comments_count")

기존에 가지고 있는 'created_at' 필드만 정렬이 가능함 

 시도해 본 것들

django order by로 구글 검색

annotate 키워드 발견

annotate() ≒ lambda()

람다가 함수를 임시로 생성해서 사용하는 것 처럼

annotate()는 field를 임시로 만들어준다. 

Article.objects.annotate(comments_count=Count("comment")).order_by("-comments_count")

"comment"는 

class Comment(models.Model):
    article = models.ForeignKey(Article, verbose_name="게시글", on_delete=models.CASCADE)
    user = models.ForeignKey(User, verbose_name="작성자", on_delete=models.CASCADE)
    content = models.CharField("내용", max_length=300)

article을 ForeingKey로 가지고있는 Comment를 가져와서 사용한다. 

그리고 그것을 comments_count=를 통해서 필드명을 지정해주고.order_by()로 정렬한다. 

 

comments_count = serializers.SerializerMethodField()

def get_comments_count(self, obj):
        return obj.comment_set.count()

그리고 serializer를 통해서 개수를 센 것을 보여준다. 

serializer의 필드와 annotate()의 필드는 전혀 영향을 주지 않는 별개의 기능을 수행한다. 

 해결 방법

def get(self, request):
        articles = Article.objects.all()
        current_order = request.query_params.get("order", None)
        if current_order == "outdated":
            articles = Article.objects.order_by("created_at")
        elif current_order == "likes":
            articles = Article.objects.annotate(likes_count=Count("like")).order_by(
                "-likes_count")
        elif current_order == "comments":
            articles = Article.objects.annotate(
                comments_count=Count("comment")
            ).order_by("-comments_count")
        elif current_order == None:
            articles = Article.objects.order_by("-created_at")

 알게 된 점

사용방법이 다를 뿐 구조 자체는 비슷한 명령어가 패키지에 많다는 것을 느꼈다. 

annotate()를 통해서 임시로 Article에 필드로 활용한다.

뭔가 정리가 안되는 것 같아서 살펴보자 정렬 자체는 serailizer와 상관없이 annotate()단독으로 가능했다.

serailizer의 필드는 단순히 결과를 보여줄 수 있도록 세어주는 것이고 기능 자체에 영향을 주지는 않는다.