나는 이렇게 논다/Suulgo_# 술취향 매칭

#4_난 당신의 술 취향을 알고 있다.

daco2020 2022. 1. 22. 18:37
반응형

상대의 술 취향을 알 수 있는 상세페이지?

우리의 서비스는 유저와 유저 간에 술 취향을 매칭 하여 연결시켜주는 매칭 서비스이다. 그렇기 때문에 우리가 유저에게 제공해주는 정보는 다른 유저들의 정보일 수밖에 없다.

 

나는 상세페이지를 맡았으므로 고객이 선택한 다른 유저의 정보, 즉 상세페이지 뷰를 구현하였다. 내가 프론트에게 넘겨주는 정보는 다음과 같다. 처음에는 디비 테이블에 있는 칼럼명을 그대로 사용하여 반환하였는데, 워낙 정보가 많다 보니 프론트와 상의하여 앞에 'text'와 'alcohol'을 붙여 데이터를 더 쉽게 구분하여 사용할 수 있도록 하였다.

 

#결과 반환값

{
    "result": {
        "id": 1,
        "profile_image_url": "http://www.irobotnews.com/news/photo/201709/11610_26562_331.png",
        "text_name": "류지후",
        "text_email": "vo@example.net",
        "text_gender": "남",
        "text_mbti_title": "ENFP",
        "text_mbti_description": "재기발랄한 활동가",
        "text_class_number": 28,
        "text_comment": "술은 모두 달다.1",
        "text_favorite_place": "유럽 지중해1",
        "text_favorite_food": "엽떡1",
        "text_favorite_hobby": "니트1",
        "text_stack": "백",
        "alcohol_limit": {
            "반병": false
        },
        "alcohol_level": {
            "11~20": false
        },
        "alcohol_drinking_methods": [
            {
                "샷": false
            },
            {
                "탄산수": false
            }
        ],
        "alcohol_categories": [
            {
                "진": false
            },
            {
                "위스키": true
            }
        ],
        "alcohol_flavors": [
            {
                "싱그러운": true
            },
            {
                "묵직": true
            },
            {
                "달콤": true
            }
        ]
    }
}

그런데 반환 값을 보면 특이한 점이 있다. 아래 alcohol이 붙은 항목들은 그 안에 불린 값이 추가로 반환된다. 왜 일까?

 

 

우리의 취향이 일치하면 True True True !

상대의 정보를 반환하는 것은 어렵지 않다. 그냥 DB에 있는 그대로 쏴주기만 하면 되니까. 하지만 상대의 정보를 그냥 단순히 보여주기만 해서는 서비스의 퀄리티가 낮을 수밖에 없다. 나와 취향이 일치하는지 일일이 대조해봐야 하기 때문이다. 그래서 우리는 기획단계 때부터 본인과 상대의 취향이 일치하는 항목들은 따로 표시를 하여 고객이 서비스를 더 편하고 정확하게 이용할 수 있도록 목표를 잡았다.

 

이를 위해서는 일치 여부 확인이 필요한 항목들을 따로 선정하고 그 항목들에 한해서 코드를 이용해 일치 여부를 판별해내었다. 코드는 다음과 같다.

# views.py

class ProductView(View):
    @authorization
    def get(self, request, product_id):
        try:
            product                 = Survey.objects.get(user=product_id)
            user                    = Survey.objects.get(user=request.user)
            user_drinking_methods   = [user_drinking.drinking_method for user_drinking in user.surveydrinkingmethod_set.all().prefetch_related("drinking_method")]
            user_alcohol_categories = [user_alcohol_category.alcohol_category for user_alcohol_category in user.surveyalcoholcategory_set.all().prefetch_related("alcohol_category")]
            user_flavor             = [user_flavor.flavor for user_flavor in user.surveyflavor_set.all().prefetch_related("flavor")]

	    #딕셔너리가 여기 왜 있게? 
            stack_dict = {1:"프론트", 2:"백"}
            alcohol_limit_dict = {1:"알쓰", 2:"반병", 3:"한병", 4:"N병"}

            result = {
                "id"                       : product.user.id,
                "profile_image_url"        : product.user.profile_image_url,
                "text_name"                : product.user.name,
                "text_email"               : product.user.email,
                "text_gender"              : product.gender.name,
                "text_mbti_title"          : product.mbti.name,
                "text_mbti_description"    : product.mbti.information,
                "text_class_number"        : product.class_number,
                "text_comment"             : product.comment,
                "text_favorite_place"      : product.favorite_place, 
                "text_favorite_food"       : product.favorite_food, 
                "text_favorite_hobby"      : product.hobby,
                "text_stack"               : stack_dict.get(product.stack),
                "alcohol_limit"            : { alcohol_limit_dict.get(product.alcohol_limit) : product.alcohol_limit == user.alcohol_limit },
                "alcohol_level"            : { product.alcohol_level : product.alcohol_level == user.alcohol_level },
                "alcohol_drinking_methods" : [{
                    product_drinking.drinking_method.name : product_drinking.drinking_method in user_drinking_methods
                    } for product_drinking in product.surveydrinkingmethod_set.all().prefetch_related("drinking_method")],
                "alcohol_categories"       : [{
                    product_alcohol_category.alcohol_category.name : product_alcohol_category.alcohol_category in user_alcohol_categories
                    } for product_alcohol_category in product.surveyalcoholcategory_set.all().prefetch_related("alcohol_category")],
                "alcohol_flavors"          : [{
                    product_flavor.flavor.name : product_flavor.flavor in user_flavor
                    } for product_flavor in product.surveyflavor_set.all().prefetch_related("flavor")],
            }

            return JsonResponse({ "result" : result }, status=200)

        except Survey.DoesNotExist:
            return JsonResponse({ "message" : "DoesNotExist" }, status=400)

뭔가 코드가 길어서 어렵게 느껴지겠지만.. 그저 변수명이 길 뿐이다.. (변수명을 짓는데도 많은 고민을 했었다ㅜㅜ)

 

 

일반적인 정보들은 그냥 찾아서 반환한다. 이 부분은 어렵지 않다. 하지만 중복선택이 있는 항목들은 모두 중간 테이블에서 확인해 가져와야 하기 때문에 리스트 컴프리핸션을 미리 돌릴 필요가 있었다. 그리고 결과 반환 값에는 해당 리스트가 유저 정보와 일치하는지 다시 한번 체크를 하고 만약 일치하는 정보가 있다면 'True' 아니라면 'False'로 반환하도록 작성하였다. 

 

또한 stack과 alcohol_limit은 텍스트로 들어오는 게 아닌 Enum을 활용하여 DB에 저장하기로 하였기 때문에 이를 다시 반환할 때에는 숫자로 저장된 정보를 문자로 바꿔줄 필요가 있었다. 하여 딕셔너리 자료구조를 활용해 if를 사용하지 않고도 값을 반환할 수 있도록 하였다. 이 부분은 병민 님, 승현 님의 조언을 참고하여 작성하였는데 if를 사용하지 않고도 값을 찾을 수 있다는 점에서 나는 큰 충격을 받았다..!(깨달음)

 

 

 

마무리

이렇게 하여 상세페이지는 상대 유저의 정보뿐만 아니라 본인과 일치하는 항목들도 모두 알 수 있게 되었다. 기존에 이런 서비스들을 자주 접했었는데, (예를 들어 소개팅 앱이나 취미, 취향 매칭 앱 같은 곳에서) 이렇게 실제 구현해보니 신기하고 재미있다는 생각이 들었다. 고객에게 한발 더 다가간 느낌이 들었고 고객이 더 만족할 수 있는 서비스를 제공하려면 어떻게 해야 하지?라는 궁금증도 생겼다. 이러한 생각은 이후 만들게 될 ‘술 취향 매칭 알고리즘’을 짜는 데에도 큰 동기부여가 되었다.

 

 


 

+추가 내용

취향 일치 여부 키-값 형식이 다루기 어렵고 모호하여 추후 수정하였다.

 

 

 

반응형