From c559f150bba48677c8c454b502475a6424a79274 Mon Sep 17 00:00:00 2001 From: dkfla Date: Fri, 2 Aug 2024 21:35:12 +0900 Subject: [PATCH 01/18] =?UTF-8?q?feat:=20=ED=8F=89=EA=B7=A0=20=EB=B3=84?= =?UTF-8?q?=EC=A0=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- restaurants/serializers.py | 25 ++++++++++++++++++++----- restaurants/views.py | 3 ++- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/restaurants/serializers.py b/restaurants/serializers.py index 9800570..5aef4b3 100644 --- a/restaurants/serializers.py +++ b/restaurants/serializers.py @@ -5,16 +5,14 @@ class RestaurantSerializer(serializers.ModelSerializer): - reviews = serializers.SerializerMethodField() + rating_average = serializers.SerializerMethodField() class Meta: model = Restaurant fields = "__all__" - def get_reviews(self, obj): - reviews = obj.reviews.order_by("-recommend_count")[:4] - serializer = ReviewSerializer(reviews, many=True) - return serializer.data + def get_rating_average(self, obj): + return obj.rating_average() class RestaurantListSerializer(serializers.ModelSerializer): @@ -44,3 +42,20 @@ class UserRestaurantListSerializer(serializers.ModelSerializer): class Meta: model = UserRestaurantsList fields = "__all__" + + +class RestaurantDetailSerializer(serializers.ModelSerializer): + reviews = serializers.SerializerMethodField() + rating_average = serializers.SerializerMethodField() + + class Meta: + model = Restaurant + fields = "__all__" + + def get_reviews(self, obj): + reviews = obj.reviews.order_by("-recommend_count")[:4] + serializer = ReviewSerializer(reviews, many=True) + return serializer.data + + def get_rating_average(self, obj): + return obj.rating_average() diff --git a/restaurants/views.py b/restaurants/views.py index 2e6f8eb..3abfc7a 100644 --- a/restaurants/views.py +++ b/restaurants/views.py @@ -8,6 +8,7 @@ RestaurantListSerializer, SearchHistorySerializer, UserRestaurantListSerializer, + RestaurantDetailSerializer, ) # from django.contrib.auth.decorators import login_required @@ -108,7 +109,7 @@ def add_remove_restaurant(request, pk): def restaurant_detail(request, pk): try: restaurant = Restaurant.objects.prefetch_related("reviews").get(pk=pk) - serializer = RestaurantSerializer(restaurant) + serializer = RestaurantDetailSerializer(restaurant) return Response(serializer.data) except Restaurant.DoesNotExist: return Response( From 955e4241681700a86b449e65a946fb5084dec346 Mon Sep 17 00:00:00 2001 From: dkfla Date: Fri, 2 Aug 2024 22:08:53 +0900 Subject: [PATCH 02/18] =?UTF-8?q?feat:=20=EA=B2=80=EC=83=89=20=EA=B8=B0?= =?UTF-8?q?=EB=A1=9D=20=EC=82=AD=EC=A0=9C=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- restaurants/serializers.py | 2 +- restaurants/views.py | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/restaurants/serializers.py b/restaurants/serializers.py index 5aef4b3..25ed3a1 100644 --- a/restaurants/serializers.py +++ b/restaurants/serializers.py @@ -33,7 +33,7 @@ def get_rating_average(self, obj): class SearchHistorySerializer(serializers.ModelSerializer): class Meta: model = SearchHistory - fields = ["query", "timestamp"] + fields = ["id", "query", "timestamp"] class UserRestaurantListSerializer(serializers.ModelSerializer): diff --git a/restaurants/views.py b/restaurants/views.py index 3abfc7a..6885cb7 100644 --- a/restaurants/views.py +++ b/restaurants/views.py @@ -26,7 +26,7 @@ def restaurant_list(request): @csrf_exempt -@api_view(["GET", "POST"]) +@api_view(["GET", "POST", "DELETE"]) # @login_required def search(request): user = User.objects.get(id=21) # 임시 유저 지정, 추후 삭제 @@ -50,6 +50,18 @@ def search(request): logging.debug("Serialized data: %s", data) return Response({"results": data}) + elif request.method == "DELETE": + history_id = request.data.get("id", "") + if not history_id: + return Response({"error": "No history ID provided"}, status=400) + + try: + history_to_delete = SearchHistory.objects.get(id=history_id, user=user) + history_to_delete.delete() + return Response({"message": "Search history deleted successfully"}) + except SearchHistory.DoesNotExist: + return Response({"error": "No matching search history found"}, status=404) + else: return Response({"error": "Unsupported method"}, status=405) From 52cefaf8a8a0163bfee14167db4d7f18efab0576 Mon Sep 17 00:00:00 2001 From: dkfla Date: Fri, 2 Aug 2024 23:23:06 +0900 Subject: [PATCH 03/18] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- friends/serializers.py | 12 +++++++++++- friends/urls.py | 3 ++- friends/views.py | 24 +++++++++++++++++++++++- mustgou/urls.py | 2 +- 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/friends/serializers.py b/friends/serializers.py index a44ccd1..a34c8b7 100644 --- a/friends/serializers.py +++ b/friends/serializers.py @@ -1,12 +1,22 @@ from rest_framework import serializers from .models import Friend from restaurants.models import Restaurant, UserRestaurantsList +from accounts.models import User + + +class UserSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = ["name", "profile_img", "reliability"] class FriendSerializer(serializers.ModelSerializer): + user = UserSerializer(read_only=True) + friend = UserSerializer(read_only=True) + class Meta: model = Friend - fields = "__all__" + fields = ["user", "friend", "state"] class RestaurantSerializer(serializers.ModelSerializer): diff --git a/friends/urls.py b/friends/urls.py index 7d66cd4..d504dba 100644 --- a/friends/urls.py +++ b/friends/urls.py @@ -3,8 +3,9 @@ urlpatterns = [ path( - "/restaurants/", + "friends//restaurants/", views.friend_restaurant_list, name="friend-restaurant-list", ), + path("friends/", views.friend_list, name="friend-list"), ] diff --git a/friends/views.py b/friends/views.py index 0d02607..83d2af0 100644 --- a/friends/views.py +++ b/friends/views.py @@ -5,8 +5,10 @@ # from django.contrib.auth.decorators import login_required from restaurants.models import UserRestaurantsList -from .serializers import RestaurantSerializer +from .serializers import RestaurantSerializer, FriendSerializer from accounts.models import User +from .models import Friend +from django.views.decorators.csrf import csrf_exempt @api_view(["GET"]) @@ -25,3 +27,23 @@ def friend_restaurant_list(request, id): return Response( {"message": "Friend not found"}, status=status.HTTP_404_NOT_FOUND ) + + +@csrf_exempt +@api_view(["GET"]) +# @login_required +def friend_list(request): + user = User.objects.get(id=21) + + friend_request = Friend.objects.filter(friend=user, state="request") + friend_request_serialized = FriendSerializer(friend_request, many=True).data + + friend_approve = Friend.objects.filter(user=user, state="approve") + friend_approve_serialized = FriendSerializer(friend_approve, many=True).data + + data = { + "friend_request": friend_request_serialized, + "friends": friend_approve_serialized, + } + + return Response(data) diff --git a/mustgou/urls.py b/mustgou/urls.py index 354332d..c7ec8dd 100644 --- a/mustgou/urls.py +++ b/mustgou/urls.py @@ -21,5 +21,5 @@ path("admin/", admin.site.urls), path("", include("restaurants.urls")), path("auth/", include("accounts.urls")), - path("friends/", include("friends.urls")), + path("", include("friends.urls")), ] From b63b91c417e43e9d0b437fdb11882ae864201ae1 Mon Sep 17 00:00:00 2001 From: dkfla Date: Fri, 2 Aug 2024 23:39:40 +0900 Subject: [PATCH 04/18] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EB=A7=8C=20=EC=9D=91=EB=8B=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- friends/serializers.py | 11 +++++++++-- friends/views.py | 10 +++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/friends/serializers.py b/friends/serializers.py index a34c8b7..a1c8337 100644 --- a/friends/serializers.py +++ b/friends/serializers.py @@ -10,13 +10,20 @@ class Meta: fields = ["name", "profile_img", "reliability"] -class FriendSerializer(serializers.ModelSerializer): +class FriendRequestSerializer(serializers.ModelSerializer): user = UserSerializer(read_only=True) + + class Meta: + model = Friend + fields = ["user", "state"] + + +class FriendSerializer(serializers.ModelSerializer): friend = UserSerializer(read_only=True) class Meta: model = Friend - fields = ["user", "friend", "state"] + fields = ["friend", "state"] class RestaurantSerializer(serializers.ModelSerializer): diff --git a/friends/views.py b/friends/views.py index 83d2af0..74207a9 100644 --- a/friends/views.py +++ b/friends/views.py @@ -5,7 +5,7 @@ # from django.contrib.auth.decorators import login_required from restaurants.models import UserRestaurantsList -from .serializers import RestaurantSerializer, FriendSerializer +from .serializers import RestaurantSerializer, FriendSerializer, FriendRequestSerializer from accounts.models import User from .models import Friend from django.views.decorators.csrf import csrf_exempt @@ -36,14 +36,14 @@ def friend_list(request): user = User.objects.get(id=21) friend_request = Friend.objects.filter(friend=user, state="request") - friend_request_serialized = FriendSerializer(friend_request, many=True).data + friend_request_serialized = FriendRequestSerializer(friend_request, many=True).data - friend_approve = Friend.objects.filter(user=user, state="approve") - friend_approve_serialized = FriendSerializer(friend_approve, many=True).data + friends = Friend.objects.filter(user=user, state="approve") + friends_serialized = FriendSerializer(friends, many=True).data data = { "friend_request": friend_request_serialized, - "friends": friend_approve_serialized, + "friends": friends_serialized, } return Response(data) From cd4e0cedeca8a7bf4b59e2addb00fd83a5da68d8 Mon Sep 17 00:00:00 2001 From: dkfla Date: Sat, 3 Aug 2024 00:35:50 +0900 Subject: [PATCH 05/18] =?UTF-8?q?feat:=20=ED=95=A8=EA=BB=98=20=EC=A0=80?= =?UTF-8?q?=EC=9E=A5=ED=95=9C=20=EC=8B=9D=EB=8B=B9=20=EC=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- friends/serializers.py | 25 +++++++++++++++++++++++-- friends/views.py | 26 ++++++++++++++++---------- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/friends/serializers.py b/friends/serializers.py index a1c8337..15bd3ec 100644 --- a/friends/serializers.py +++ b/friends/serializers.py @@ -7,15 +7,36 @@ class UserSerializer(serializers.ModelSerializer): class Meta: model = User - fields = ["name", "profile_img", "reliability"] + fields = ["id", "name", "profile_img", "reliability"] class FriendRequestSerializer(serializers.ModelSerializer): user = UserSerializer(read_only=True) + common_restaurant_count = serializers.SerializerMethodField() class Meta: model = Friend - fields = ["user", "state"] + fields = ["user", "state", "common_restaurant_count"] + + def get_common_restaurant_count(self, obj): + try: + user = obj.user + # friend_user = self.context.get('request').user + friend_user = User.objects.get(id=21) + + user_restaurants = set( + UserRestaurantsList.objects.filter(user=user).values_list( + "restaurant_id", flat=True + ) + ) + friend_restaurants = set( + UserRestaurantsList.objects.filter(user=friend_user).values_list( + "restaurant_id", flat=True + ) + ) + return len(user_restaurants.intersection(friend_restaurants)) + except User.DoesNotExist: + return 0 class FriendSerializer(serializers.ModelSerializer): diff --git a/friends/views.py b/friends/views.py index 74207a9..05b23fb 100644 --- a/friends/views.py +++ b/friends/views.py @@ -33,17 +33,23 @@ def friend_restaurant_list(request, id): @api_view(["GET"]) # @login_required def friend_list(request): - user = User.objects.get(id=21) + try: + user = User.objects.get(id=21) + + friend_request = Friend.objects.filter(friend=user, state="request") + friend_request_serialized = FriendRequestSerializer( + friend_request, context={"request": request}, many=True + ).data - friend_request = Friend.objects.filter(friend=user, state="request") - friend_request_serialized = FriendRequestSerializer(friend_request, many=True).data + friends = Friend.objects.filter(user=user, state="approve") + friends_serialized = FriendSerializer(friends, many=True).data - friends = Friend.objects.filter(user=user, state="approve") - friends_serialized = FriendSerializer(friends, many=True).data + data = { + "friend_request": friend_request_serialized, + "friends": friends_serialized, + } - data = { - "friend_request": friend_request_serialized, - "friends": friends_serialized, - } + return Response(data) - return Response(data) + except User.DoesNotExist: + return Response({"message": "User not found"}, status=status.HTTP_404_NOT_FOUND) From c5ce13c747e37d58a89cbbbb59952b060731ac1b Mon Sep 17 00:00:00 2001 From: Shim Kyumin Date: Sat, 3 Aug 2024 16:01:47 +0900 Subject: [PATCH 06/18] =?UTF-8?q?fix:=20API=20=EB=AA=85=EC=84=B8=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EB=A6=AC?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=8B=9C=EB=A6=AC=EC=96=BC=EB=9D=BC?= =?UTF-8?q?=EC=9D=B4=EC=A0=80=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- friends/serializers.py | 15 +++++++++++++-- friends/views.py | 8 ++++++-- restaurants/serializers.py | 13 ++++++++++++- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/friends/serializers.py b/friends/serializers.py index 15bd3ec..661ec6f 100644 --- a/friends/serializers.py +++ b/friends/serializers.py @@ -47,6 +47,17 @@ class Meta: fields = ["friend", "state"] +class RestaurantlistSerializer(serializers.ModelSerializer): + rating_average = serializers.SerializerMethodField() + + class Meta: + model = Restaurant + fields = ["name", "rating_average", "latitude", "longitude"] + + def get_rating_average(self, obj): + return obj.rating_average() + + class RestaurantSerializer(serializers.ModelSerializer): # reviews = serializers.SerializerMethodField() @@ -55,8 +66,8 @@ class Meta: fields = "__all__" -class RestaurantSerializer(serializers.ModelSerializer): - restaurant = RestaurantSerializer() +class FriendRestaurantSerializer(serializers.ModelSerializer): + restaurant = RestaurantlistSerializer() class Meta: model = UserRestaurantsList diff --git a/friends/views.py b/friends/views.py index 05b23fb..e6b551b 100644 --- a/friends/views.py +++ b/friends/views.py @@ -5,7 +5,11 @@ # from django.contrib.auth.decorators import login_required from restaurants.models import UserRestaurantsList -from .serializers import RestaurantSerializer, FriendSerializer, FriendRequestSerializer +from .serializers import ( + FriendSerializer, + FriendRequestSerializer, + FriendRestaurantSerializer, +) from accounts.models import User from .models import Friend from django.views.decorators.csrf import csrf_exempt @@ -20,7 +24,7 @@ def friend_restaurant_list(request, id): # 친구의 맛집 리스트를 가져옴 friend_restaurants = UserRestaurantsList.objects.filter(user=friend) - serializer = RestaurantSerializer(friend_restaurants, many=True) + serializer = FriendRestaurantSerializer(friend_restaurants, many=True) return Response({"restaurants": serializer.data}, status=status.HTTP_200_OK) except User.DoesNotExist: diff --git a/restaurants/serializers.py b/restaurants/serializers.py index 25ed3a1..c51e969 100644 --- a/restaurants/serializers.py +++ b/restaurants/serializers.py @@ -36,8 +36,19 @@ class Meta: fields = ["id", "query", "timestamp"] +class RestaurantlistSerializer(serializers.ModelSerializer): + rating_average = serializers.SerializerMethodField() + + class Meta: + model = Restaurant + fields = ["name", "rating_average", "latitude", "longitude"] + + def get_rating_average(self, obj): + return obj.rating_average() + + class UserRestaurantListSerializer(serializers.ModelSerializer): - restaurant = RestaurantSerializer() + restaurant = RestaurantlistSerializer() class Meta: model = UserRestaurantsList From 0d89096e6a1a70eda44090a23e4883af066d17f6 Mon Sep 17 00:00:00 2001 From: Shim Kyumin Date: Sat, 3 Aug 2024 16:16:28 +0900 Subject: [PATCH 07/18] =?UTF-8?q?feat:=20=EB=A0=88=EC=8A=A4=ED=86=A0?= =?UTF-8?q?=EB=9E=91=20=EB=AA=A8=EB=8D=B8=EC=97=90=20=EC=9D=8C=EC=8B=9D=20?= =?UTF-8?q?=EB=B6=84=EB=A5=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0005_restaurant_food_type.py | 17 +++++++++++++++++ restaurants/models.py | 1 + 2 files changed, 18 insertions(+) create mode 100644 restaurants/migrations/0005_restaurant_food_type.py diff --git a/restaurants/migrations/0005_restaurant_food_type.py b/restaurants/migrations/0005_restaurant_food_type.py new file mode 100644 index 0000000..769417c --- /dev/null +++ b/restaurants/migrations/0005_restaurant_food_type.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.14 on 2024-08-03 07:13 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("restaurants", "0004_userrestaurantslist"), + ] + + operations = [ + migrations.AddField( + model_name="restaurant", + name="food_type", + field=models.CharField(blank=True, max_length=20, null=True), + ), + ] diff --git a/restaurants/models.py b/restaurants/models.py index b06a37b..522e095 100644 --- a/restaurants/models.py +++ b/restaurants/models.py @@ -6,6 +6,7 @@ class Restaurant(models.Model): name = models.CharField(max_length=255) + food_type = models.CharField(max_length=20, null=True, blank=True) rating_naver = models.DecimalField( max_digits=5, decimal_places=2, null=True, blank=True ) From 2ff787583ac9426a86e5bc8f1719b09028cda471 Mon Sep 17 00:00:00 2001 From: Shim Kyumin Date: Sat, 3 Aug 2024 16:18:44 +0900 Subject: [PATCH 08/18] =?UTF-8?q?feat:=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=8B=9C=EB=A6=AC=EC=96=BC=EB=9D=BC=EC=9D=B4=EC=A0=80=EC=97=90?= =?UTF-8?q?=20=EC=9D=8C=EC=8B=9D=20=EB=B6=84=EB=A5=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- friends/serializers.py | 2 +- restaurants/serializers.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/friends/serializers.py b/friends/serializers.py index 661ec6f..0de4d1c 100644 --- a/friends/serializers.py +++ b/friends/serializers.py @@ -52,7 +52,7 @@ class RestaurantlistSerializer(serializers.ModelSerializer): class Meta: model = Restaurant - fields = ["name", "rating_average", "latitude", "longitude"] + fields = ["name", "food_type", "rating_average", "latitude", "longitude"] def get_rating_average(self, obj): return obj.rating_average() diff --git a/restaurants/serializers.py b/restaurants/serializers.py index c51e969..70dc09e 100644 --- a/restaurants/serializers.py +++ b/restaurants/serializers.py @@ -41,7 +41,7 @@ class RestaurantlistSerializer(serializers.ModelSerializer): class Meta: model = Restaurant - fields = ["name", "rating_average", "latitude", "longitude"] + fields = ["name", "food_type", "rating_average", "latitude", "longitude"] def get_rating_average(self, obj): return obj.rating_average() From d2995351e14ef8534d3cf40467cccd81fcf2ed86 Mon Sep 17 00:00:00 2001 From: Shim Kyumin Date: Sat, 3 Aug 2024 16:27:20 +0900 Subject: [PATCH 09/18] =?UTF-8?q?fix:=20=EB=B9=BC=EB=A8=B9=EC=9D=80=20?= =?UTF-8?q?=EC=8B=9D=EB=8B=B9=20id=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- friends/serializers.py | 2 +- restaurants/serializers.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/friends/serializers.py b/friends/serializers.py index 0de4d1c..7851345 100644 --- a/friends/serializers.py +++ b/friends/serializers.py @@ -52,7 +52,7 @@ class RestaurantlistSerializer(serializers.ModelSerializer): class Meta: model = Restaurant - fields = ["name", "food_type", "rating_average", "latitude", "longitude"] + fields = ["id", "name", "food_type", "rating_average", "latitude", "longitude"] def get_rating_average(self, obj): return obj.rating_average() diff --git a/restaurants/serializers.py b/restaurants/serializers.py index 70dc09e..74fcfca 100644 --- a/restaurants/serializers.py +++ b/restaurants/serializers.py @@ -41,7 +41,7 @@ class RestaurantlistSerializer(serializers.ModelSerializer): class Meta: model = Restaurant - fields = ["name", "food_type", "rating_average", "latitude", "longitude"] + fields = ["id", "name", "food_type", "rating_average", "latitude", "longitude"] def get_rating_average(self, obj): return obj.rating_average() From 5fd98bb1ea470f35729421b588a7f647ecce745b Mon Sep 17 00:00:00 2001 From: GalaxyDimension Date: Sat, 3 Aug 2024 17:31:32 +0900 Subject: [PATCH 10/18] =?UTF-8?q?feat:=20=EC=9D=8C=EC=8B=9D=20=EB=B6=84?= =?UTF-8?q?=EB=A5=98=20=ED=81=AC=EB=A1=A4=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crawling.py | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/crawling.py b/crawling.py index c641710..3409264 100644 --- a/crawling.py +++ b/crawling.py @@ -1,6 +1,7 @@ # selenium의 webdriver를 사용하기 위한 import from selenium import webdriver from selenium.webdriver.common.by import By +from selenium.webdriver.common.keys import Keys import pandas as pd @@ -11,7 +12,7 @@ driver = webdriver.Chrome() # 크롬 드라이버에 url 주소 넣고 실행 -driver.get("http://www.moamodu.com/develop/daum_map.php") +driver.get("https://map.kakao.com/") # 페이지가 완전히 로딩되도록 4초 동안 기다림 time.sleep(4) @@ -58,24 +59,42 @@ def get_lag_lng(address): return lagtitude, longitude +def get_type(restaurant_name): + search_box = driver.find_element(By.ID, "search.keyword.query") + search_box.send_keys(restaurant_name) + search_box.send_keys(Keys.RETURN) + time.sleep(3) + + try: + rtype = driver.find_element(By.CLASS_NAME, "subcategory") + type = rtype.text + except Exception: + type = "null" + + time.sleep(1) + + # 검색어 창 비우기 + search_box.clear() + + return type + + # Load the CSV file -file_path = "kakao_test.csv" +file_path = "final.csv" data = pd.read_csv(file_path) # 칼럼 추가 -data["Latitude"] = None -data["Longitude"] = None +data["Type"] = None -# 식당 주소로 위도 경도 획득 후 입력 +# 식당으로 타입 획득 후 입력 for index, row in data.iterrows(): - restaurant_address = row["Address"] - lagtitude, longitude = get_lag_lng(restaurant_address) - data.at[index, "Latitude"] = lagtitude - data.at[index, "Longitude"] = longitude + restaurant_address = row["Name"] + type = get_type(restaurant_address) + data.at[index, "Type"] = type time.sleep(1) # 데이터 저장 -data.to_csv("kakao_latlng_add.csv", encoding="utf-8-sig", index=False) +data.to_csv("restauranttype.csv", encoding="utf-8-sig", index=False) # 브라우저 닫기 driver.quit() From 985ecb381c46ebf431c7c04cbbbe95554ab4243e Mon Sep 17 00:00:00 2001 From: dkfla Date: Sat, 3 Aug 2024 22:32:40 +0900 Subject: [PATCH 11/18] =?UTF-8?q?feat:=20food=5Ftype=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- restaurants/serializers.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/restaurants/serializers.py b/restaurants/serializers.py index 74fcfca..7124756 100644 --- a/restaurants/serializers.py +++ b/restaurants/serializers.py @@ -21,7 +21,9 @@ class RestaurantListSerializer(serializers.ModelSerializer): class Meta: model = Restaurant fields = [ + "id", "name", + "food_type", "rating_average", "address", ] From 521530b89126dcdfda5994a0100c3b5d6a0a4f1d Mon Sep 17 00:00:00 2001 From: Shim Kyumin Date: Sun, 4 Aug 2024 17:49:37 +0900 Subject: [PATCH 12/18] =?UTF-8?q?fix:=20=EB=A0=88=EC=8A=A4=ED=86=A0?= =?UTF-8?q?=EB=9E=91=EC=97=90=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20url=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0006_restaurant_image_url.py | 17 +++++++++++++++++ restaurants/models.py | 1 + 2 files changed, 18 insertions(+) create mode 100644 restaurants/migrations/0006_restaurant_image_url.py diff --git a/restaurants/migrations/0006_restaurant_image_url.py b/restaurants/migrations/0006_restaurant_image_url.py new file mode 100644 index 0000000..8bbd7a0 --- /dev/null +++ b/restaurants/migrations/0006_restaurant_image_url.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.14 on 2024-08-04 08:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("restaurants", "0005_restaurant_food_type"), + ] + + operations = [ + migrations.AddField( + model_name="restaurant", + name="image_url", + field=models.URLField(blank=True, max_length=500, null=True), + ), + ] diff --git a/restaurants/models.py b/restaurants/models.py index 522e095..b010332 100644 --- a/restaurants/models.py +++ b/restaurants/models.py @@ -19,6 +19,7 @@ class Restaurant(models.Model): address = models.CharField(max_length=255) latitude = models.DecimalField(max_digits=11, decimal_places=8) longitude = models.DecimalField(max_digits=11, decimal_places=8) + image_url = models.URLField(max_length=500, null=True, blank=True) def rating_average(self): ratings = [self.rating_naver, self.rating_kakao, self.rating_google] From 3c9c6728e991e56d52c10cd67de45469cdc9554d Mon Sep 17 00:00:00 2001 From: Shim Kyumin Date: Sun, 4 Aug 2024 18:05:45 +0900 Subject: [PATCH 13/18] =?UTF-8?q?fix:=20=EB=82=B4=20=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=9D=91=EB=8B=B5=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- restaurants/serializers.py | 10 +++++++++- restaurants/views.py | 19 +++++++++++++------ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/restaurants/serializers.py b/restaurants/serializers.py index 7124756..e959175 100644 --- a/restaurants/serializers.py +++ b/restaurants/serializers.py @@ -43,7 +43,15 @@ class RestaurantlistSerializer(serializers.ModelSerializer): class Meta: model = Restaurant - fields = ["id", "name", "food_type", "rating_average", "latitude", "longitude"] + fields = [ + "id", + "name", + "food_type", + "rating_average", + "latitude", + "longitude", + "image_url", + ] def get_rating_average(self, obj): return obj.rating_average() diff --git a/restaurants/views.py b/restaurants/views.py index 6885cb7..61dd7f1 100644 --- a/restaurants/views.py +++ b/restaurants/views.py @@ -7,7 +7,7 @@ RestaurantSerializer, RestaurantListSerializer, SearchHistorySerializer, - UserRestaurantListSerializer, + RestaurantlistSerializer, RestaurantDetailSerializer, ) @@ -70,11 +70,18 @@ def search(request): @api_view(["GET"]) # @login_required def user_restaurant_list(request): - user = User.objects.get(id=21) # 임시 유저 지정, 추후 삭제 - user_restaurants = UserRestaurantsList.objects.filter(user=user) # 추후 삭제 - # user_restaurants = UserRestaurantsList.objects.filter(user=request.user) - serializer = UserRestaurantListSerializer(user_restaurants, many=True) - return Response(serializer.data, status=status.HTTP_200_OK) + try: + user = User.objects.get(id=21) # 임시 유저 지정, 추후 삭제 + user_restaurants = UserRestaurantsList.objects.filter(user=user) # 추후 삭제 + # user_restaurants = UserRestaurantsList.objects.filter(user=request.user) + restaurant_ids = user_restaurants.values_list("restaurant_id", flat=True) + restaurants = Restaurant.objects.filter(id__in=restaurant_ids) + serializer = RestaurantlistSerializer(restaurants, many=True) + return Response({"results": serializer.data}, status=status.HTTP_200_OK) + except User.DoesNotExist: + return Response( + {"message": "Default user not found"}, status=status.HTTP_404_NOT_FOUND + ) @csrf_exempt From a2779fac642c66886abc5edc5f3c5fd09484e689 Mon Sep 17 00:00:00 2001 From: Shim Kyumin Date: Sun, 4 Aug 2024 18:15:47 +0900 Subject: [PATCH 14/18] =?UTF-8?q?fix:=20=EC=B9=9C=EA=B5=AC=20=EC=8B=9D?= =?UTF-8?q?=EB=8B=B9=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- friends/serializers.py | 11 ++++++++++- friends/views.py | 11 +++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/friends/serializers.py b/friends/serializers.py index 7851345..21da8a4 100644 --- a/friends/serializers.py +++ b/friends/serializers.py @@ -52,7 +52,16 @@ class RestaurantlistSerializer(serializers.ModelSerializer): class Meta: model = Restaurant - fields = ["id", "name", "food_type", "rating_average", "latitude", "longitude"] + fields = [ + "id", + "name", + "food_type", + "rating_average", + "address", + "latitude", + "longitude", + "image_url", + ] def get_rating_average(self, obj): return obj.rating_average() diff --git a/friends/views.py b/friends/views.py index e6b551b..8668491 100644 --- a/friends/views.py +++ b/friends/views.py @@ -4,11 +4,11 @@ from rest_framework import status # from django.contrib.auth.decorators import login_required -from restaurants.models import UserRestaurantsList +from restaurants.models import UserRestaurantsList, Restaurant from .serializers import ( FriendSerializer, FriendRequestSerializer, - FriendRestaurantSerializer, + RestaurantlistSerializer, ) from accounts.models import User from .models import Friend @@ -24,9 +24,12 @@ def friend_restaurant_list(request, id): # 친구의 맛집 리스트를 가져옴 friend_restaurants = UserRestaurantsList.objects.filter(user=friend) - serializer = FriendRestaurantSerializer(friend_restaurants, many=True) + restaurant_ids = friend_restaurants.values_list("restaurant_id", flat=True) + restaurants = Restaurant.objects.filter(id__in=restaurant_ids) - return Response({"restaurants": serializer.data}, status=status.HTTP_200_OK) + serializer = RestaurantlistSerializer(restaurants, many=True) + + return Response({"results": serializer.data}, status=status.HTTP_200_OK) except User.DoesNotExist: return Response( {"message": "Friend not found"}, status=status.HTTP_404_NOT_FOUND From a648a099271f7714583a8317273772b6ec1f54a3 Mon Sep 17 00:00:00 2001 From: Shim Kyumin Date: Sun, 4 Aug 2024 18:19:43 +0900 Subject: [PATCH 15/18] =?UTF-8?q?fix:=20=EC=9D=91=EB=8B=B5=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=ED=95=84=EC=9A=94=EC=97=86=EB=8A=94=20=EC=A3=BC?= =?UTF-8?q?=EC=86=8C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- friends/serializers.py | 1 - 1 file changed, 1 deletion(-) diff --git a/friends/serializers.py b/friends/serializers.py index 21da8a4..9836516 100644 --- a/friends/serializers.py +++ b/friends/serializers.py @@ -57,7 +57,6 @@ class Meta: "name", "food_type", "rating_average", - "address", "latitude", "longitude", "image_url", From 23bbb284f8c3f59aff5dffb946e24836f81444e4 Mon Sep 17 00:00:00 2001 From: dkfla Date: Sun, 4 Aug 2024 20:29:56 +0900 Subject: [PATCH 16/18] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EC=B6=94?= =?UTF-8?q?=EC=B2=9C=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- friends/serializers.py | 42 +++++++++++++ friends/urls.py | 1 + friends/views.py | 63 +++++++++++++++++++ .../0003_alter_review_restaurant.py | 23 +++++++ 4 files changed, 129 insertions(+) create mode 100644 reviews/migrations/0003_alter_review_restaurant.py diff --git a/friends/serializers.py b/friends/serializers.py index 9836516..f7c9ead 100644 --- a/friends/serializers.py +++ b/friends/serializers.py @@ -39,6 +39,48 @@ def get_common_restaurant_count(self, obj): return 0 +class FriendRecommendSerializer(serializers.ModelSerializer): + common_restaurant_count = serializers.SerializerMethodField() + common_restaurants = serializers.SerializerMethodField() + + class Meta: + model = User + fields = [ + "id", + "name", + "profile_img", + "reliability", + "common_restaurant_count", + "common_restaurants", + ] + + def get_common_restaurant_count(self, obj): + user = self.context.get("user") + user_restaurants = set( + UserRestaurantsList.objects.filter(user=user).values_list( + "restaurant_id", flat=True + ) + ) + friend_restaurants = set( + UserRestaurantsList.objects.filter(user=obj).values_list( + "restaurant_id", flat=True + ) + ) + return len(user_restaurants.intersection(friend_restaurants)) + + def get_common_restaurants(self, obj): + user = self.context.get("user") + user_restaurants = set( + UserRestaurantsList.objects.filter(user=user).values_list( + "restaurant_id", flat=True + ) + ) + friend_restaurants = UserRestaurantsList.objects.filter( + user=obj, restaurant_id__in=user_restaurants + ).values("restaurant__name", "restaurant__image_url")[:2] + return friend_restaurants + + class FriendSerializer(serializers.ModelSerializer): friend = UserSerializer(read_only=True) diff --git a/friends/urls.py b/friends/urls.py index d504dba..efafd47 100644 --- a/friends/urls.py +++ b/friends/urls.py @@ -8,4 +8,5 @@ name="friend-restaurant-list", ), path("friends/", views.friend_list, name="friend-list"), + path("friend-recommend/", views.friend_recommend, name="friend-recommend"), ] diff --git a/friends/views.py b/friends/views.py index 8668491..f2e1830 100644 --- a/friends/views.py +++ b/friends/views.py @@ -9,10 +9,13 @@ FriendSerializer, FriendRequestSerializer, RestaurantlistSerializer, + FriendRecommendSerializer, ) from accounts.models import User from .models import Friend from django.views.decorators.csrf import csrf_exempt +from django.db.models import Count, Q +import random @api_view(["GET"]) @@ -51,12 +54,72 @@ def friend_list(request): friends = Friend.objects.filter(user=user, state="approve") friends_serialized = FriendSerializer(friends, many=True).data + user_restaurants = set( + UserRestaurantsList.objects.filter(user=user).values_list( + "restaurant_id", flat=True + ) + ) + potential_friends = ( + User.objects.exclude(id=user.id) + .annotate( + common_restaurant_count=Count( + "userrestaurantslist__restaurant_id", + filter=Q(userrestaurantslist__restaurant_id__in=user_restaurants), + ) + ) + .order_by("-common_restaurant_count")[:7] + ) + + friend_recommend_serialized = FriendRecommendSerializer( + potential_friends, many=True, context={"request": request, "user": user} + ).data + data = { "friend_request": friend_request_serialized, "friends": friends_serialized, + "friend_recommend": friend_recommend_serialized, } return Response(data) except User.DoesNotExist: return Response({"message": "User not found"}, status=status.HTTP_404_NOT_FOUND) + + +@csrf_exempt +@api_view(["GET"]) +# @login_required +def friend_recommend(request): + try: + user = User.objects.get(id=21) + + user_restaurants = set( + UserRestaurantsList.objects.filter(user=user).values_list( + "restaurant_id", flat=True + ) + ) + potential_friends = ( + User.objects.exclude(id=user.id) + .annotate( + common_restaurant_count=Count( + "userrestaurantslist__restaurant_id", + filter=Q(userrestaurantslist__restaurant_id__in=user_restaurants), + ) + ) + .order_by("-common_restaurant_count")[:7] + ) + + if potential_friends: + random_friend = random.choice(potential_friends) + friend_recommend_serialized = FriendRecommendSerializer( + random_friend, context={"request": request, "user": user} + ).data + return Response({"friend_recommend": friend_recommend_serialized}) + + return Response( + {"message": "No recommended friends found"}, + status=status.HTTP_404_NOT_FOUND, + ) + + except User.DoesNotExist: + return Response({"message": "User not found"}, status=status.HTTP_404_NOT_FOUND) diff --git a/reviews/migrations/0003_alter_review_restaurant.py b/reviews/migrations/0003_alter_review_restaurant.py new file mode 100644 index 0000000..0b774ab --- /dev/null +++ b/reviews/migrations/0003_alter_review_restaurant.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.14 on 2024-08-04 11:14 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + dependencies = [ + ("restaurants", "0005_restaurant_food_type"), + ("reviews", "0002_alter_recommend_user_alter_review_user"), + ] + + operations = [ + migrations.AlterField( + model_name="review", + name="restaurant", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="reviews", + to="restaurants.restaurant", + ), + ), + ] From e8b7e6c7a7efe5b069b1563418d959d7ba9acde7 Mon Sep 17 00:00:00 2001 From: dkfla Date: Sun, 4 Aug 2024 21:02:07 +0900 Subject: [PATCH 17/18] =?UTF-8?q?chore:=20=EC=9D=91=EB=8B=B5=20=EC=96=91?= =?UTF-8?q?=EC=8B=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- friends/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/friends/views.py b/friends/views.py index f2e1830..f59d06d 100644 --- a/friends/views.py +++ b/friends/views.py @@ -114,7 +114,7 @@ def friend_recommend(request): friend_recommend_serialized = FriendRecommendSerializer( random_friend, context={"request": request, "user": user} ).data - return Response({"friend_recommend": friend_recommend_serialized}) + return Response(friend_recommend_serialized) return Response( {"message": "No recommended friends found"}, From 16fe8e0bdd1cd32f3de217cdf796065a4554a53c Mon Sep 17 00:00:00 2001 From: dkfla Date: Mon, 5 Aug 2024 00:45:33 +0900 Subject: [PATCH 18/18] =?UTF-8?q?feat:=20=EB=AA=A8=EB=8D=B8=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- friends/models.py | 26 +++++++++++++++++++++----- friends/serializers.py | 38 +++++++++++++++++++++++++++++++------- friends/views.py | 15 ++++++++++----- 3 files changed, 62 insertions(+), 17 deletions(-) diff --git a/friends/models.py b/friends/models.py index 3f0404b..15c93ae 100644 --- a/friends/models.py +++ b/friends/models.py @@ -5,12 +5,28 @@ class Friend(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="friends") + friend = models.ForeignKey(User, on_delete=models.CASCADE, related_name="friend_of") + + class Meta: + unique_together = ("user", "friend") + + +class FriendRequest(models.Model): STATE_CHOICES = [ - ("request", "Request"), - ("approve", "Approve"), - ("deny", "Deny"), + ("pending", "Pending"), + ("accepted", "Accepted"), + ("declined", "Declined"), ] - user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="friends") - friend = models.ForeignKey(User, on_delete=models.CASCADE, related_name="friend_of") + from_user = models.ForeignKey( + User, on_delete=models.CASCADE, related_name="sent_friend_requests" + ) + to_user = models.ForeignKey( + User, on_delete=models.CASCADE, related_name="received_friend_requests" + ) + created_at = models.DateTimeField(auto_now_add=True) state = models.CharField(max_length=20, choices=STATE_CHOICES, default="request") + + class Meta: + unique_together = ("from_user", "to_user") diff --git a/friends/serializers.py b/friends/serializers.py index f7c9ead..13aee59 100644 --- a/friends/serializers.py +++ b/friends/serializers.py @@ -1,5 +1,5 @@ from rest_framework import serializers -from .models import Friend +from .models import Friend, FriendRequest from restaurants.models import Restaurant, UserRestaurantsList from accounts.models import User @@ -11,16 +11,25 @@ class Meta: class FriendRequestSerializer(serializers.ModelSerializer): - user = UserSerializer(read_only=True) + id = serializers.IntegerField(source="from_user.id") + name = serializers.CharField(source="from_user.name") + profile_img = serializers.URLField(source="from_user.profile_img.url") + reliability = serializers.IntegerField(source="from_user.reliability") common_restaurant_count = serializers.SerializerMethodField() class Meta: - model = Friend - fields = ["user", "state", "common_restaurant_count"] + model = FriendRequest + fields = [ + "id", + "name", + "profile_img", + "reliability", + "common_restaurant_count", + ] def get_common_restaurant_count(self, obj): try: - user = obj.user + user = obj.from_user # friend_user = self.context.get('request').user friend_user = User.objects.get(id=21) @@ -80,13 +89,28 @@ def get_common_restaurants(self, obj): ).values("restaurant__name", "restaurant__image_url")[:2] return friend_restaurants + def to_representation(self, instance): + representation = super().to_representation(instance) + include_restaurants = self.context.get("include_restaurants", False) + if not include_restaurants: + representation.pop("common_restaurants") + return representation + class FriendSerializer(serializers.ModelSerializer): - friend = UserSerializer(read_only=True) + id = serializers.IntegerField(source="friend.id") + name = serializers.CharField(source="friend.name") + profile_img = serializers.URLField(source="friend.profile_img.url") + reliability = serializers.IntegerField(source="friend.reliability") class Meta: model = Friend - fields = ["friend", "state"] + fields = [ + "id", + "name", + "profile_img", + "reliability", + ] class RestaurantlistSerializer(serializers.ModelSerializer): diff --git a/friends/views.py b/friends/views.py index f59d06d..39406c6 100644 --- a/friends/views.py +++ b/friends/views.py @@ -12,7 +12,7 @@ FriendRecommendSerializer, ) from accounts.models import User -from .models import Friend +from .models import Friend, FriendRequest from django.views.decorators.csrf import csrf_exempt from django.db.models import Count, Q import random @@ -44,14 +44,15 @@ def friend_restaurant_list(request, id): # @login_required def friend_list(request): try: + # user = request.user user = User.objects.get(id=21) - friend_request = Friend.objects.filter(friend=user, state="request") + friend_request = FriendRequest.objects.filter(to_user=user, state="pending") friend_request_serialized = FriendRequestSerializer( friend_request, context={"request": request}, many=True ).data - friends = Friend.objects.filter(user=user, state="approve") + friends = Friend.objects.filter(user=user) friends_serialized = FriendSerializer(friends, many=True).data user_restaurants = set( @@ -71,7 +72,9 @@ def friend_list(request): ) friend_recommend_serialized = FriendRecommendSerializer( - potential_friends, many=True, context={"request": request, "user": user} + potential_friends, + many=True, + context={"request": request, "user": user, "include_restaurants": False}, ).data data = { @@ -91,6 +94,7 @@ def friend_list(request): # @login_required def friend_recommend(request): try: + # user = request.user user = User.objects.get(id=21) user_restaurants = set( @@ -112,7 +116,8 @@ def friend_recommend(request): if potential_friends: random_friend = random.choice(potential_friends) friend_recommend_serialized = FriendRecommendSerializer( - random_friend, context={"request": request, "user": user} + random_friend, + context={"request": request, "user": user, "include_restaurants": True}, ).data return Response(friend_recommend_serialized)