카테고리 없음

[Django]쿼리 최적화(GroupConcat->select_related().prefetch_related()/Dto 공부)

잠이와요 2023. 7. 26. 21:26
story_place_subquery = Story.objects.filter(id=story_id).values('place')

        same_place_story = Story.objects.filter(place=Subquery(story_place_subquery)).exclude(id=story_id).annotate(
            place_name=F('place__place_name'),
            writer_is_verified=F('writer__is_verified'),
            nickname=F('writer__nickname'),
            extra_pics=GroupConcat('photos__image'))

        for story in same_place_story:
            story.rep_pic = story.rep_pic.url
            if story.extra_pics is not None:
                story.extra_pics = map(
                    append_media_url, story.extra_pics.split(',')[:3])

        return same_place_story
story_place_subquery = Story.objects.filter(
            id=story_id
        ).values('place')

        same_place_story = Story.objects.filter(place=Subquery(story_place_subquery)).select_related(
                'writer', 'place'
            ).prefetch_related(
                'photos'
            ).exclude(id=story_id)
        

        same_place_story_dto = StoryDto(
            id = same_place_story.id,
            title = same_place_story.title,
            preview=same_place_story.preview,
            rep_pic=same_place_story.rep_pic.image.url,
            extra_pics=[photo.image.url for photo in same_place_story.photos.all()],
            place_name=same_place_story.place.place_name,
            writer_is_verified=same_place_story.writer.writer_is_verified,
            nickname= same_place_story.writer.nickname,
            created=same_place_story.created,
            story_review=None,
            html_content=None,
            tag=None,
            views=None,
            story_like=None,
            like_cnt=None,
            comment_cnt=None,
            category=None,
            semi_category=None,
            writer=None,
            profile=None,
            map_image=None,
            writer_is_followed=None,
        )

same_place_story는 쿼리셋이므로 직접 id, title, preview 등과 같이 속성에 접근할 수 없습니다. 대신 same_place_story는 여러 개의 객체를 담고 있는 쿼리셋이므로, 이를 순회하면서 각 객체에 대한 정보를 StoryDto 객체로 변환하여 리스트에 추가해야 합니다.

또한, rep_pic, extra_pics, place_name, writer_is_verified, nickname, created 등의 정보는 쿼리셋 내부에서 다룰 수 있으며, 더 이상 Subquery를 사용할 필요가 없습니다. 이 정보들은 select_related와 prefetch_related를 사용하여 이미 미리 로드되었습니다.

class SamePlaceStorySelector:
    def __init__(self, user:User):
        self.user = user
    
    def list(self, story_id: int):
        story_place_subquery = Story.objects.filter(id=story_id).values('place')

        same_place_stories = Story.objects.filter(place=Subquery(story_place_subquery)).select_related('writer', 'place').prefetch_related('photos').exclude(id=story_id)

        story_dtos = []

        for story in same_place_stories:
                extra_pics = [photo.image.url for photo in story.photos.all()[:3]]
                story_dto = StoryDto(
                    id=story.id,
                    title=story.title,
                    place_name=story.place.place_name,
                    story_review=None,
                    preview=story.preview,
                    html_content=None,
                    tag=None,
                    views=None,
                    story_like=None,
                    like_cnt=None,
                    comment_cnt=None,
                    category=None,
                    semi_category=None,
                    writer=story.writer,
                    writer_is_verified=story.writer.is_verified,
                    nickname=story.writer.nickname,
                    profile=None,
                    created=story.created,
                    map_image=None,
                    rep_pic=story.rep_pic.url,
                    extra_pics=extra_pics,
                    writer_is_followed=None,
                )
                story_dtos.append(story_dto)

        return story_dtos

view 에 many=Ture 없으니까 에러남. 다시 보자

 

class SamePlaceStorySelector:
    def __init__(self, user:User):
        self.user = user
    
    def list(self, story_id: int):
        story_place_subquery = Story.objects.filter(id=story_id).values('place')

        same_place_stories = Story.objects.filter(place=Subquery(story_place_subquery)).select_related('writer', 'place').prefetch_related('photos').exclude(id=story_id)

        story_dtos = []

        for story in same_place_stories:
                extra_pics = [photo.image.url for photo in story.photos.all()[:3]]
                story_dto = SamePlaceStoryDto(
                    id=story.id,
                    title=story.title,
                    place_name=story.place.place_name,
                    preview=story.preview,
                    writer=story.writer,
                    writer_is_verified=story.writer.is_verified,
                    nickname=story.writer.nickname,
                    created=story.created,
                    rep_pic=story.rep_pic.url,
                    extra_pics=extra_pics,
                )
                story_dtos.append(story_dto)

        return story_dtos

원래 Dto에서 None 쓰는건 있을수도 있고 없을수도 있는 필드라서 그런것.