1、项目介绍

技术栈
Python 语言、Django 框架、Vue 前端框架、MySQL 数据库、Echarts 可视化库、HTML、基于用户的协同过滤推荐算法

功能模块

  • 首页美食信息模块
  • 美食数据大屏模块
  • 评分信息记录模块
  • 我的评论模块
  • 我的收藏模块
  • 美食推荐模块
  • 注册登录模块
  • 管理员界面模块
  • 个人中心模块
  • 美食数据管理模块

项目介绍
本系统是基于 Python 与 Django 开发的美食推荐可视化平台,融合用户协同过滤算法为用户提供个性化美食推荐。系统首页集中展示各类美食基础信息,支持搜索与筛选。美食数据大屏通过 Echarts 呈现美食类型、发布时间、评分分布、收藏数区间及最受欢迎 TOP10 等多维度可视化图表。用户可对美食进行评分、评论与收藏,个人中心集中管理个人资料及互动记录。推荐模块基于用户评分行为,有评分记录时按用户偏好类型精准推荐,无记录时随机推荐 12 款美食以增加发现机会。后台管理员可对美食信息、用户数据进行增删改查与批量操作,保障平台数据准确性与运营规范性。

2、项目界面

(1)首页美食信息
该页面是美食推荐可视化平台的核心操作页,设有后台管理入口,支持美食名称的搜索与重置操作,可展示美食的各类基础信息及评分、评论、收藏相关数据,还能实现数据可视化展示与个性化推荐,同时配备个人信息查看、密码修改和系统退出的基础功能模块。
在这里插入图片描述

(2)美食数据大屏
该页面是美食推荐可视化平台的数据可视化分析大屏,设有后台管理入口,可通过各类图表可视化呈现美食类型、发布时间、分类的分布情况,还能展示美食评分和收藏数的区间分布数据,同时呈现最受欢迎TOP10美食相关数据,实现美食多维度数据的直观可视化展示与分析。

在这里插入图片描述

(3)评分信息记录
该页面是美食推荐可视化平台的评分信息管理页,设有后台管理入口,可展示用户的我的评分相关数据列表,包含评分对应的各类相关信息,支持对评分记录执行删除操作,同时可切换查看美食、评论、收藏等信息及进行数据可视化、个性化推荐操作,也配备个人信息查看、密码修改和系统退出功能。

在这里插入图片描述

(4)我的评论
该页面是美食推荐可视化平台的评论信息管理页,设有后台管理入口,核心展示用户的我的评论数据列表,呈现评论内容、时间等相关信息,支持分页查看评论数据,可切换至美食、评分、收藏等信息板块,也能进行数据可视化、个性化推荐操作,同时配备个人信息查看、密码修改和系统退出的基础功能。

在这里插入图片描述

(5)我的收藏
该页面是美食推荐可视化平台的收藏信息管理页,设有后台管理入口,核心展示用户的我的收藏数据列表,呈现收藏对应的美食编号、收藏时间等信息,支持对收藏记录执行取消收藏操作,可切换至美食、评分、评论等信息板块,也能进行数据可视化、个性化推荐操作,同时配备个人信息查看、密码修改和系统退出的基础功能。

在这里插入图片描述

(6)美食推荐
该页面是美食推荐可视化平台的个性化推荐页,设有后台管理入口,核心展示系统为用户推荐的各类美食信息,呈现美食的类型、分类、评分等基础信息及相关数据,可切换至美食、评分、评论、收藏等信息板块,也能进行数据可视化操作,同时配备个人信息查看、密码修改和系统退出的基础功能。

在这里插入图片描述

(7)注册登录
该页面是美食推荐可视化平台的账号登录页,设有后台管理入口,核心提供账号密码输入框和登录操作按钮,支持管理员相关登录权限选择,配备注册入口供新用户创建账号,同时展示平台的核心服务与功能亮点,为用户提供平台的登录与注册基础操作功能。

在这里插入图片描述

(8)管理员界面
该页面是美食推荐可视化平台的后台美食管理页,支持管理员进行美食信息的搜索、重置与新增操作,可展示美食的标题、评分、类型等全量信息,能对单条美食数据执行编辑、删除和查看详情的操作,同时配备用户管理相关功能入口,实现后台对美食数据的全方位管理与操作。

在这里插入图片描述

(9)个人中心
该页面是美食推荐可视化平台的个人信息管理页,设有后台管理入口,核心展示用户的用户名、姓名、电话等个人基础信息,支持对个人信息进行编辑并保存修改,可切换至美食、评分、评论等信息板块,也能进行数据可视化、个性化推荐操作,同时配备修改密码和系统退出的基础功能。
在这里插入图片描述

(10)美食数据管理
该页面是美食推荐可视化平台的高级后台美食管理页,支持主题切换与美食信息搜索,可批量选择和删除美食数据,能展示美食的评分、热度等全维度详细信息,同时配备收藏记录、用户、评分管理等功能入口,实现对美食数据的批量操作和全平台数据的综合管理。

在这里插入图片描述

3、项目说明

一、技术栈简要说明
系统后端采用 Python 语言与 Django 框架构建,前端使用 Vue 框架实现响应式交互,数据库选用 MySQL 进行数据存储。可视化部分通过 Echarts 图表库实现美食类型分布、评分区间、收藏数排行等多种数据图表的渲染展示。推荐模块基于用户协同过滤算法,根据用户历史评分行为生成个性化推荐结果。

二、功能模块详细介绍
· 首页美食信息模块
作为平台核心操作页,集中展示各类美食的名称、图片、简介、所属品类等基础信息,支持按美食名称进行搜索与重置筛选,同时展示评分、评论、收藏等相关数据,并配备数据可视化与个性化推荐入口。

· 美食数据大屏模块
基于 Echarts 构建的数据可视化分析大屏,通过多种图表直观呈现美食类型分布、发布时间趋势、分类占比、评分区间分布、收藏数区间分布以及最受欢迎 TOP10 美食等数据,实现多维度数据的可视化展示。

· 评分信息记录模块
管理用户对美食的评分行为记录,展示评分分值、评分时间、对应美食名称等信息,支持对个人评分记录进行删除操作,为推荐模块提供核心数据来源。

· 我的评论模块
用户个人评论管理板块,以列表形式展示用户发布的评论内容、评论时间等信息,支持分页查看,用户可管理自己的美食评价与反馈。

· 我的收藏模块
用户收藏功能管理页面,展示用户收藏的美食列表及收藏时间,支持取消收藏操作,方便用户快速查找与管理心仪美食。

· 美食推荐模块
平台核心功能,基于用户协同过滤算法,根据用户历史评分行为动态生成推荐结果。有评分记录时按用户偏好美食类型精准推荐,无评分记录时随机推荐 12 款美食,兼顾推荐精准性与多样性。

· 注册登录模块
基础账号功能页面,提供账号密码输入框与登录操作按钮,支持新用户注册与老用户登录,是用户使用评分、评论、收藏等个性化功能的前提。

· 管理员界面模块
后台美食管理入口,支持管理员进行美食信息的搜索、重置与新增操作,可对单条美食数据执行编辑、删除和详情查看,同时配备用户管理功能入口,实现后台数据全方位管控。

· 个人中心模块
用户个人信息管理页面,展示用户名、姓名、电话等基础信息,支持编辑保存个人资料,同时提供修改密码功能,整合用户个性化操作入口。

· 美食数据管理模块
高级后台管理功能,支持主题切换与美食信息搜索,可批量选择与删除美食数据,展示评分、热度等全维度详细信息,同时配备收藏记录、用户管理、评分管理等入口,实现全平台数据的综合管理。

三、项目总结
本系统是基于 Python 与 Django 开发的美食推荐可视化平台,融合用户协同过滤算法为用户提供个性化美食推荐服务。系统首页集中展示美食基础信息并支持搜索筛选,美食数据大屏通过 Echarts 呈现类型分布、评分区间、收藏排行等多维度可视化图表。用户可对美食进行评分、评论与收藏,个人中心集中管理个人资料与互动记录。推荐模块基于用户评分行为,有记录时按偏好类型精准推荐,无记录时随机推荐 12 款美食以增加发现机会。后台提供管理员界面与美食数据管理功能,支持美食信息的增删改查与批量操作,保障平台数据准确性与运营规范性。

4、核心代码

from django.shortcuts import render,redirect
from django.core.paginator import Paginator
# Create your views here.
from .utils import getPublicData
from .utils import getFenxiData
from .utils.error import *
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
import json
from .crud_base import CRUDBase
import pymysql

def tuijian(request):
    if request.method == 'POST':
        data = json.loads(request.body)
        userid = data['userid']
        print(userid)
        # 获取用户评分过的漫画类型
        user_rated_types = getPublicData.querys(
            """
            SELECT DISTINCT m.style 
            FROM mh m 
            INNER JOIN rate r ON r.prodid = m.id 
            WHERE r.userid = %s
            """, 
            [userid], 
            'select'
        )
        
        # 如果用户有评分记录,推荐相同类型的漫画
        if user_rated_types:
            style_list = [t[0] for t in user_rated_types]
            style_conditions = " OR ".join(["style = %s"] * len(style_list))
            
            # 获取相同类型的其他漫画
            datalist = getPublicData.querys(
                f"""
                SELECT * FROM mh 
                WHERE {style_conditions}
                ORDER BY RAND() 
                LIMIT 12
                """,
                style_list,
                'select'
            )
        else:
            # 如果用户没有评分记录,随机推荐漫画
            datalist = getPublicData.querys(
                "SELECT * FROM mh ORDER BY RAND() LIMIT 12",
                [],
                'select'
            )

        # 构建返回数据
        data_list = []
        fields = ['id', 'title', 'detail_url', 'style', 'area', 'price', 
                 'status', 'authors', 'description', 'cover_url', 'froms']
        
        for item in datalist:
            node = {}
            for index, field in enumerate(fields):
                node[field] = item[index]
            data_list.append(node)
            
        return JsonResponse({'code': '200', 'msg': '成功', 'data': data_list})



def adminupdate(request):
    if request.method == 'PUT':
        data = json.loads(request.body)
        print(data)
        id = data['id']
        username = data['username']
        name = data['name']
        role = data['role']
        phone = data['phone']
        q = "update admin set username = '" + username  + "',name='" + name + "',role='" + role + "',phone='" + phone + "'where id = " + str(
            id)
        getPublicData.querys(q, [], 'no_select')
        return JsonResponse({'code': '200', 'msg': '成功', 'data': None})
def adminupdatePassword(request):
    if request.method == 'PUT':
        data = json.loads(request.body)
        print(data)
        id = data['id']
        newPassword = data['newPassword']

        q = "update admin set password = '" + newPassword + "'where id = " + str(
            id)

        getPublicData.querys(q, [], 'no_select')
        return JsonResponse({'code': '200', 'msg': '成功', 'data': None})


def personupdate(request):
    if request.method == 'PUT':
        data = json.loads(request.body)
        print(data)
        id = data['id']
        username = data['username']
        name = data['name']
        role = data['role']
        phone = data['phone']
        q = "update user set username = '" + username  + "',name='" + name + "',role='" + role + "',phone='" + phone + "'where id = " + str(
           id)

        getPublicData.querys(q,[],'no_select')
        return JsonResponse({'code': '200', 'msg': '成功', 'data': None})
def personupdatePassword(request):
    if request.method == 'PUT':
        data = json.loads(request.body)
        print(data)
        id = data['id']
        password = data['newPassword']

        q = "update user set password = '" + password   + "'where id = " + str(
           id)

        getPublicData.querys(q,[],'no_select')
        return JsonResponse({'code': '200', 'msg': '成功', 'data': None})






class UserCRUD(CRUDBase):
    def __init__(self):
        super().__init__(
            table_name='user',
            fields=['id', 'username', 'password', 'name', 'role', 'phone'],
            required_fields = ['username', 'password']  # 设置必填字段
        )
    def list(self, request) -> JsonResponse:
        if request.method != 'POST':
            return JsonResponse({'code': '5004', 'msg': '请求方法错误', 'data': None})
        try:
            data = json.loads(request.body)
            username = data.get('username')
            if username:
                sql = f'''SELECT * FROM `{self.table_name}` 
                          WHERE username LIKE CONCAT('%%', %s, '%%')'''
                result = getPublicData.querys(sql, [username], 'select')
            else:
                sql = f'SELECT * FROM `{self.table_name}`'
                result = getPublicData.querys(sql, [], 'select')

            # 格式化返回数据
            data_list = []
            for item in result:
                node = {}
                for index, field in enumerate(self.fields):
                    node[field] = item[index]
                data_list.append(node)

            return JsonResponse({'code': '200', 'data': {'list': data_list}})

        except Exception as e:
            return JsonResponse({'code': '5004', 'msg': str(e), 'data': None})

user_crud = UserCRUD()

def userlist(request):
    return user_crud.list(request)

def useradd(request):
    return user_crud.add(request)

def userdelete(request):
    return user_crud.delete(request)

def userupdate(request):
    return user_crud.update(request)




class CommentCRUD(CRUDBase):
    def __init__(self):
        super().__init__(
            table_name='comment',
            fields=['id', 'content', 'userid', 'prodid', 'time'],
            required_fields = ['content', 'userid', 'prodid']  # 设置必填字段
        )

comment_crud = CommentCRUD()

def commentlist(request):
    return comment_crud.list(request)

def commentadd(request):
    return comment_crud.add(request)

def commentdelete(request):
    return comment_crud.delete(request)

def commentupdate(request):
    return comment_crud.update(request)

class RateCRUD(CRUDBase):
    def __init__(self):
        super().__init__(
            table_name='rate',
            fields=['id', 'score', 'userid', 'prodid', 'time'],
            required_fields = ['score', 'userid', 'prodid']  # 设置必填字段
        )

rate_crud = RateCRUD()

def ratelist(request):
    return rate_crud.list(request)

def rateadd(request):
    return rate_crud.add(request)

def ratedelete(request):
    return rate_crud.delete(request)

def rateupdate(request):
    return rate_crud.update(request)

class CollectCRUD(CRUDBase):
    def __init__(self):
        super().__init__(
            table_name='collect',
            fields=['id', 'userid', 'prodid', 'time'],
            required_fields = ['userid', 'prodid']
        )

collect_crud = CollectCRUD()

def collectlist(request):
    return collect_crud.list(request)

def collectadd(request):
    return collect_crud.add(request)

def collectdelete(request):
    return collect_crud.delete(request)

def collectupdate(request):
    return collect_crud.update(request)



def login(request):
    if request.method =='GET':
        return render(request, 'Login.html')
    else:
        data =json.loads(request.body)
        print(data)
        username = data['username']
        password = data['password']
        role = data['role']
        print(username, password, role)
        if role=='ADMIN':
            users =getPublicData.querys(f"select * from `admin` where username='{username}' and password='{password}'", [],'select')
            if users:
                    return JsonResponse({'code': '200', 'data': {
                        'role': users[0][4],
                        'id': users[0][0],
                        'name': users[0][3],
                        'password': users[0][2],
                        'phone': users[0][5],
                        'username': users[0][1],
                    }})
            else:
                    return JsonResponse({'code': '5004', 'msg': '用户不存在', 'data': None})


        else:
            users = getPublicData.querys(f"select * from `user` where username='{username}' and password='{password}'",
                                         [], 'select')
            if users:
                return JsonResponse({'code': '200', 'data': {
                    'role': users[0][4],
                    'id': users[0][0],
                    'name': users[0][3],
                    'password': users[0][2],
                    'phone': users[0][5],
                    'username': users[0][1],
                }})
            else:
                return JsonResponse({'code': '5004', 'msg': '用户不存在', 'data': None})
def registry(request):
    if request.method == 'POST':
        data = json.loads(request.body)
        print(data)
        username = data['username']
        password = data['password']
        name = data['name']
        role = data['role']
        phone = data['phone']
        getPublicData.querys('''insert into user(username,password,name,role,phone) values(%s,%s,%s,%s,%s) ''',
           [username, password, name, role,phone])
        return JsonResponse({'code': '200', 'msg': '注册成功', 'data': None})

def logOut(request):
    request.session.clear()
    return redirect('login')

class FoodCRUD(CRUDBase):
    def __init__(self):
        super().__init__(
            table_name='food',
            fields=['id', 'title', 'cover', 'score', 'redu', 'sc', 
                   'biaoqian', 'yuanliao', 'js', 'shijian', 'type', 
                   'category', 'fbr', 'fbrdetail', 'detail']
        )

food_crud = FoodCRUD()

def food_list(request):
    return food_crud.list(request)

def food_add(request):
    return food_crud.add(request)

def food_delete(request):
    return food_crud.delete(request)

def food_update(request):
    return food_crud.update(request)

def get_food_analysis(request):
    try:
        data = {
            'type_data': getFenxiData.get_food_type_count(),
            'category_data': getFenxiData.get_food_category_count(),
            'rate_data': getFenxiData.get_top_rated_food(),
            'collect_data': getFenxiData.get_top_collected_food(),
            'comment_data': getFenxiData.get_top_commented_food(),
            'popular_data': getFenxiData.get_most_popular_food()
        }
        return JsonResponse({'code': '200', 'msg': '成功', 'data': data})
    except Exception as e:
        return JsonResponse({'code': '5004', 'msg': f'获取分析数据失败:{str(e)}', 'data': None})

def get_time_distribution(request):
    if request.method == 'GET':
        try:
            data = getFenxiData.get_time_distribution()
            return JsonResponse({
                'code': '200',
                'msg': '成功',
                'data': [
                    {
                        'time_period': item[0],
                        'count': item[1]
                    }
                    for item in data
                ]
            })
        except Exception as e:
            return JsonResponse({
                'code': '5004',
                'msg': f'获取时间分布统计失败:{str(e)}',
                'data': None
            })

def get_score_distribution(request):
    if request.method == 'GET':
        try:
            data = getFenxiData.get_score_distribution()
            return JsonResponse({
                'code': '200',
                'msg': '成功',
                'data': [
                    {
                        'score_range': item[0],
                        'count': item[1]
                    }
                    for item in data
                ]
            })
        except Exception as e:
            return JsonResponse({
                'code': '5004',
                'msg': f'获取评分分布统计失败:{str(e)}',
                'data': None
            })

def get_collection_distribution(request):
    if request.method == 'GET':
        try:
            data = getFenxiData.get_collection_distribution()
            return JsonResponse({
                'code': '200',
                'msg': '成功',
                'data': [
                    {
                        'collection_range': item[0],
                        'count': item[1]
                    }
                    for item in data
                ]
            })
        except Exception as e:
            return JsonResponse({
                'code': '5004',
                'msg': f'获取收藏分布统计失败:{str(e)}',
                'data': None
            })

更多推荐