diff --git a/MoviesRecommend/movie/__pycache__/views.cpython-38.pyc b/MoviesRecommend/movie/__pycache__/views.cpython-38.pyc index bbad21c..f8ef471 100644 Binary files a/MoviesRecommend/movie/__pycache__/views.cpython-38.pyc and b/MoviesRecommend/movie/__pycache__/views.cpython-38.pyc differ diff --git a/MoviesRecommend/movie/views.py b/MoviesRecommend/movie/views.py index 1a92159..4260706 100644 --- a/MoviesRecommend/movie/views.py +++ b/MoviesRecommend/movie/views.py @@ -105,4 +105,109 @@ class SearchView(ListView): 'current_page': current_page, 'left_has_more': left_has_more, 'right_has_more': right_has_more - } \ No newline at end of file + } + + # 推荐电影视图 + class RecommendMovieView(ListView): + model = Movie + template_name = 'movie/recommend.html' + paginate_by = 15 + context_object_name = 'movies' + ordering = 'movie_rating__score' + page_kwarg = 'p' + + def __init__(self): + super().__init__() + # 最相似的20个用户 + self.K = 20 + # 推荐出10本书 + self.N = 10 + # 存放当前用户评分过的电影querySet + self.cur_user_movie_qs = None + + # 获取用户相似度 + def get_user_sim(self): + # 用户相似度字典,格式为{ user_id1:val , user_id2:val , ... } + user_sim_dct = dict() + '''获取用户之间的相似度,存放在user_sim_dct中''' + # 获取当前用户 + cur_user_id = self.request.session['user_id'] + cur_user = User.objects.get(pk=cur_user_id) + # 获取其它用户 + other_users = User.objects.exclude(pk=cur_user_id) # 除了当前用户外的所有用户 + + # 当前用户评分过的电影 + self.cur_user_movie_qs = Movie.objects.filter(user=cur_user) + + # 计算当前用户与其他用户共同评分过的电影交集数 + for user in other_users: + # 记录感兴趣的数量 + user_sim_dct[user.id] = len(Movie.objects.filter(user=user) & self.cur_user_movie_qs) + + # 按照key排序value,返回K个最相近的用户(共同评分过的电影交集数更多) + print("user similarity calculated!") + # 格式 [ (user, value), (user, value), ... ] + return sorted(user_sim_dct.items(), key=lambda x: -x[1])[:self.K] + + # 获取推荐电影(按照相似用户总得分排序) + def get_recommend_movie(self, user_lst): + # 电影兴趣值字典,{ movie:value, movie:value , ...} + movie_val_dct = dict() + # 用户,相似度 + for user, _ in user_lst: + # 获取相似用户评分过的电影,并且不在前用户的评分列表中的,再加上score字段,方便计算兴趣值 + movie_set = Movie.objects.filter(user=user).exclude(id__in=self.cur_user_movie_qs).annotate( + score=Max('movie_rating__score')) + for movie in movie_set: + movie_val_dct.setdefault(movie, 0) + # 累计用户的评分 + movie_val_dct[movie] += movie.score + return sorted(movie_val_dct.items(), key=lambda x: -x[1])[:self.N] + + # 获取数据 + def get_queryset(self): + s = time.time() + # 获得最相似的K个用户列表 + user_lst = self.get_user_sim() + # 获得推荐电影的id + movie_lst = self.get_recommend_movie(user_lst) + # print(movie_lst) + result_lst = [] + for movie, _ in movie_lst: + result_lst.append(movie) + e = time.time() + print(f"算法推荐用时:{e - s}秒!") + return result_lst + + def get_context_data(self, *, object_list=None, **kwargs): + context = super(RecommendMovieView, self).get_context_data(*kwargs) + print(context) + paginator = context.get('paginator') + page_obj = context.get('page_obj') + pagination_data = self.get_pagination_data(paginator, page_obj) + context.update(pagination_data) + return context + + def get_pagination_data(self, paginator, page_obj, around_count=2): + current_page = page_obj.number + + if current_page <= around_count + 2: + left_pages = range(1, current_page) + left_has_more = False + else: + left_pages = range(current_page - around_count, current_page) + left_has_more = True + + if current_page >= paginator.num_pages - around_count - 1: + right_pages = range(current_page + 1, paginator.num_pages + 1) + right_has_more = False + else: + right_pages = range(current_page + 1, current_page + 1 + around_count) + right_has_more = True + return { + 'left_pages': left_pages, + 'right_pages': right_pages, + 'current_page': current_page, + 'left_has_more': left_has_more, + 'right_has_more': right_has_more + }