旅游推荐系统(view.py)

view.py

一、注册 register 和 登录 login

python 复制代码
def login(request):
    # 定义登录视图函数,接收request对象作为参数
    # request包含了用户请求的所有信息(如请求方法、POST数据、session等)
    
    if request.method == 'GET':
        # 判断请求方法是否为GET
        # GET请求通常用于获取页面,POST用于提交数据
        
        return render(request, 'login.html')
        # 如果是GET请求,直接渲染并返回登录页面
        # render函数会将login.html模板与数据结合,生成完整的HTML页面返回给用户
    
    else:
        # 如果不是GET请求,那就是POST请求(用户提交了登录表单)
        
        username = request.POST.get('username')
        # 从POST请求数据中获取username字段的值
        # request.POST类似一个字典,get方法获取键对应的值
        
        password = request.POST.get('password')
        # 从POST请求数据中获取password字段的值
        
        try:
            # 尝试执行以下代码,如果出错就跳转到except
            
            User.objects.get(username=username, password=password)
            # 使用Django ORM在User表中查询
            # 查找同时满足username和password条件的记录
            # 如果找到一条记录,说明用户名和密码正确
            # 如果找不到,会抛出异常
            
            request.session['username'] = username
            # 将用户名存入session(会话)中
            # session是服务器端记录用户状态的机制
            # 设置session后,后续请求可以通过request.session获取用户信息
            # 这实现了"登录状态"的维持
            
            return redirect('/app/home')
            # 重定向到首页
            # redirect函数会返回一个302状态码,让浏览器跳转到指定URL
            # 用户登录成功后,直接进入系统首页
        
        except:
            # 如果上面的try块中代码执行出错(比如用户不存在或密码错误)
            
            return errorResponse.errorResponse(request, '账号或密码错误')
            # 调用errorResponse模块的errorResponse方法
            # 返回一个错误页面,提示"账号或密码错误"
            # 这是一个自定义的错误处理函数

# ============================================================================

def register(request):
    # 定义注册视图函数
    # 函数名后的注释'#注册'说明了这个函数的功能
    
    if request.method == 'GET':
        # 如果是GET请求(用户点击注册链接)
        
        return render(request, 'register.html')
        # 渲染并返回注册页面
    
    else:
        # 如果是POST请求(用户提交了注册表单)
        
        username = request.POST.get('username')
        # 获取表单中的用户名
        
        password = request.POST.get('password')
        # 获取表单中的密码
        
        confirmPassword = request.POST.get('confirmPassword')
        # 获取表单中的确认密码字段
        
        try:
            # 尝试执行以下代码
            
            User.objects.get(username=username)
            # 在User表中查询是否已存在相同的用户名
            # 如果找到了,说明用户名已被注册,会抛出异常吗?不,找到了不会抛异常
            # 这里逻辑需要仔细分析
            
        except:  
            # 如果上面的get操作抛出异常(即没有找到该用户名)
            # 说明用户名可用,进入注册流程
            
            # 检查输入是否为空
            if not username or not password or not confirmPassword:
                # 如果用户名、密码或确认密码任一为空
                # not username 当username为空字符串时返回True
                
                return errorResponse.errorResponse(request, '不允许为空值')
                # 返回错误提示:不允许为空值
            
            # 检查两次密码是否一致
            if password != confirmPassword:
                # 比较密码和确认密码是否相等
                
                return errorResponse.errorResponse(request, '两次密码不一致')
                # 返回错误提示:两次密码不一致
            
            # 所有验证通过,创建新用户
            User.objects.create(username=username, password=password)
            # 使用Django ORM的create方法在User表中创建一条新记录
            # 插入用户名和密码
            
            return redirect('/app/login')
            # 注册成功后重定向到登录页面
            # 让用户用刚注册的账号登录
        
        # 如果try块中没有抛出异常(即找到了同名用户)
        return errorResponse.errorResponse(request, '该账号已存在')
        # 返回错误提示:该账号已存在
复制代码
GET请求通常用于获取页面,POST用于提交数据

登录成功后,当用户提交登录表单,服务器验证用户名密码正确后,会执行:

python 复制代码
return redirect('/app/home')

这行代码的作用是:

  • 告诉浏览器:"你刚才的请求处理完了,现在请你重新发送一个请求,去访问/app/home这个地址"

  • 浏览器收到这个指令后,会自动向/app/home发送新的请求

  • 最终用户看到的是首页内容

通俗理解:就像你去服务台办事,工作人员处理完后告诉你:"请去3号窗口领结果",然后你就走向3号窗口。

二、首页home

python 复制代码
def home(request):
    # 定义首页视图函数,处理用户访问系统首页的请求
    # request参数包含了当前HTTP请求的所有信息(用户session、请求方法、POST数据等)
    
    username = request.session.get('username')
    # 从session会话中获取当前登录用户的用户名
    # request.session是Django提供的会话对象,用于在多次请求间保持用户状态
    # get('username')方法尝试获取键为'username'的值
    # 如果用户已登录,这里会拿到用户名;如果未登录,会返回None
    # 这是在登录成功时通过request.session['username'] = username存储的
    
    userInfo = User.objects.get(username=username)
    # 根据获取到的用户名,从数据库User表中查询该用户的完整信息
    # User是之前在models.py中定义的用户模型类
    # objects.get()方法会返回满足条件的唯一一条记录
    # 这里拿到了当前登录用户的所有信息(如用户名、性别、地址、头像等)
    
    a5Len, commentsLenTitle, provienceDicSort = getHomeData.getHomeTagData()
    # 调用getHomeData模块中的getHomeTagData函数,获取首页标签数据
    # 返回三个值:
    # - a5Len:5A级景点的数量
    # - commentsLenTitle:评论数量最多的景点标题(热门景点)
    # - provienceDicSort:按省份统计的景点数量分布(字典类型,已排序)
    
    scoreTop10Data, saleCountTop10 = getHomeData.getAnthorData()
    # 调用getHomeData模块中的getAnthorData函数,获取其他统计数据
    # 返回两个值:
    # - scoreTop10Data:评分最高的前10个景点数据
    # - saleCountTop10:销量最高的前10个景点数据
    
    year, mon, day = getHomeData.getNowTime()
    # 调用getHomeData模块中的getNowTime函数,获取当前日期
    # 返回年、月、日三个整数值
    # 用于在首页显示当前时间
    
    geoData = getHomeData.getGeoData()
    # 调用getHomeData模块中的getGeoData函数,获取地理分布数据
    # 返回各地理位置的统计数据,用于在地图上展示景点分布
    
    userBarCharData = getHomeData.getUserCreateTimeData()
    # 调用getHomeData模块中的getUserCreateTimeData函数,获取用户注册时间分布数据
    # 返回用户按注册时间统计的数据,用于柱状图展示用户增长情况

    return render(request, 'home.html', {
        # 调用render函数渲染首页模板
        # 第一个参数request:当前请求对象
        # 第二个参数'home.html':要渲染的模板文件
        # 第三个参数是字典类型,向模板传递数据
        
        'userInfo': userInfo,
        # 将当前登录用户的完整信息传递给模板
        # 模板中可以通过{{ userInfo.username }}等显示用户信息
        
        'a5Len': a5Len,
        # 将5A级景点数量传递给模板
        # 用于在首页展示统计数据
        
        'commentsLenTitle': commentsLenTitle,
        # 将评论最多的景点标题传递给模板
        # 用于展示热门景点
        
        'provienceDicSort': provienceDicSort,
        # 将省份景点分布数据传递给模板
        # 用于生成按省份统计的图表
        
        'scoreTop10Data': scoreTop10Data,
        # 将评分前10的景点数据传递给模板
        # 用于展示高分景点榜单
        
        'nowTime': {
            # 将当前日期信息封装成字典传递给模板
            'year': year,  # 当前年份
            'mon': getPublicData.monthList[mon - 1],  # 当前月份
            # getPublicData.monthList是一个预定义的月份名称列表
            # mon是1-12的整数,减1后作为索引获取中文月份名
            'day': day     # 当前日期
        },
        
        'geoData': geoData,
        # 将地理分布数据传递给模板
        # 用于在地图组件中展示景点分布
        
        'userBarCharData': userBarCharData,
        # 将用户注册时间分布数据传递给模板
        # 用于生成用户增长趋势的柱状图
        
        'saleCountTop10': saleCountTop10
        # 将销量前10的景点数据传递给模板
        # 用于展示热门销量榜单
    })

session的技术定义

Session(会话) 是服务器端用来临时保存用户状态的一种机制。当用户访问网站时,服务器会为每个用户创建一个唯一的会话,并在会话中存储该用户的相关信息。

session解决了什么问题?

HTTP协议是无状态的,意思是:每次请求都是独立的,服务器不认识你是谁。

举个例子:

  1. 你登录了网站(第一次请求)

  2. 你点击"个人中心"(第二次请求)

  3. 服务器不知道第二次请求和第一次是同一个用户

session的出现就是为了解决这个问题------让服务器能记住你是谁

session在您的项目中的具体应用

登录时存储session

login函数中:

python 复制代码
request.session['username'] = username

这行代码做了什么?

  • 用户登录成功后,服务器在session中记录下他的用户名

  • 相当于服务器在自己的内存里记了一笔:"用户张三已经登录了"

首页读取session

home函数中:

python 复制代码
username = request.session.get('username')

这行代码做了什么?

  • 用户访问首页时,服务器从session中取出之前存储的用户名

  • 就知道"哦,是张三在访问"

退出时清除session

logOut函数中:

python 复制代码
del request.session['username']  # 或者 request.session.flush()

这行代码做了什么?

  • 用户退出时,服务器删除session中的记录

  • 相当于收回房卡,用户变成未登录状态

为什么需要session?

场景 没有session会怎样 有session如何解决
登录状态 每次请求都要重新输入密码 登录一次,后续请求自动识别
购物车 刷新页面购物车就空了 购物车数据保存在session中
权限控制 无法区分普通用户和管理员 session中记录用户角色
个性化推荐 不知道用户喜好 session关联用户历史行为

景点信息表(TravelInfo)详细设计

表结构

字段名 数据类型 约束 说明
id INT 主键,自增 景点唯一标识
title VARCHAR(255) 默认空字符串 景区名称
level VARCHAR(255) 默认空字符串 景区等级(如5A、4A)
discount VARCHAR(255) 默认空字符串 折扣信息
saleCount VARCHAR(255) 默认空字符串 销量
province VARCHAR(255) 默认空字符串 所在省份
star VARCHAR(255) 默认空字符串 热度评分
detailAddress VARCHAR(255) 默认空字符串 详细地址
shortIntro VARCHAR(255) 默认空字符串 简短介绍
detailUrl VARCHAR(255) 默认空字符串 详情页URL
score VARCHAR(255) 默认空字符串 用户评分
price VARCHAR(255) 默认空字符串 价格
commentsLen VARCHAR(255) 默认空字符串 评论数量
detailIntro VARCHAR(2555) 默认空字符串 详细介绍
img_list VARCHAR(2550) 默认空字符串 图片列表(JSON格式)
comments TEXT 默认空字符串 用户评论(JSON格式)
cover VARCHAR(2555) 默认空字符串 封面图片URL
createTime DATE 自动添加 数据爬取时间

字段设计说明

为什么很多字段用VARCHAR而不是数字类型?

  • 爬取的数据可能包含非数字字符,如"¥120起"、"5折"

  • 用VARCHAR可以原样存储,避免类型转换错误

  • 后续使用时再根据需要进行转换

为什么用JSON格式存储复杂数据?

  • img_listcomments是列表结构,不适合用关系表存储

  • JSON格式可以完整保留数据结构,方便解析

  • 避免了创建额外的关联表,简化设计

用户信息表(User)详细设计

表结构

字段名 数据类型 约束 说明
id INT 主键,自增 用户唯一标识
username VARCHAR(255) 默认空字符串 用户名
password VARCHAR(255) 默认空字符串 密码(明文存储,有待改进)
sex VARCHAR(255) 默认空字符串 性别
address VARCHAR(255) 默认空字符串 地址
avatar FileField 默认头像路径 头像图片
textarea VARCHAR(255) 默认空字符串 个人简介
createTime DATE 自动添加 账号创建时间

字段设计说明

密码为什么存明文?

  • 当前项目为毕业设计,简化了密码处理

  • 实际生产环境应该使用哈希加密存储

头像字段为什么用FileField?

  • Django的FileField自动处理文件上传

  • 数据库中存储的是文件路径,实际文件保存在media/avatar/目录下

三、个人信息页面changeSelfInfo

python 复制代码
def changeSelfInfo(request):
    # 定义修改个人信息的视图函数
    # 这个函数处理用户修改个人资料(如性别、地址、头像、个人简介等)的请求
    # 参数 request 包含了当前HTTP请求的所有信息(请求方法、POST数据、session等)
    
    username = request.session.get('username')
    # 从 session 会话中获取当前登录用户的用户名
    # request.session.get('username') 尝试获取键为 'username' 的值
    # 这个值是在用户登录时通过 request.session['username'] = username 存储的
    # 如果用户未登录,这里会返回 None(但中间件已经拦截了未登录用户)
    
    userInfo = User.objects.get(username=username)
    # 根据获取到的用户名,从数据库 User 表中查询该用户的完整信息
    # User 是 models.py 中定义的用户模型类
    # objects.get() 方法返回满足条件的唯一一条记录
    # 如果用户名不存在,会抛出异常(但这里用户名一定存在,因为是从 session 来的)
    # userInfo 包含了该用户的所有字段:用户名、密码、性别、地址、头像、个人简介等
    
    year, mon, day = getHomeData.getNowTime()
    # 调用 getHomeData 模块中的 getNowTime 函数,获取当前日期
    # 返回年、月、日三个整数值
    # 用于在页面顶部显示当前时间
    
    if request.method == 'POST':
        # 判断请求方法是否为 POST
        # GET 请求:用户访问修改信息页面,显示表单
        # POST 请求:用户提交修改后的信息,需要处理更新
        
        getChangeSelfInfoData.changeSelfInfo(username, request.POST, request.FILES)
        # 调用 getChangeSelfInfoData 模块中的 changeSelfInfo 函数
        # 这个函数负责实际的更新操作
        # 传入三个参数:
        #   username: 当前用户的用户名,用于定位要更新的用户记录
        #   request.POST: 包含表单中所有文本字段的数据(性别、地址、个人简介等)
        #   request.FILES: 包含上传的文件数据(如头像图片)
        # 函数内部会更新数据库中该用户的对应字段
        
        userInfo = User.objects.get(username=username)
        # 重新从数据库查询该用户的更新后信息
        # 因为上面的 changeSelfInfo 函数已经更新了数据库
        # 所以需要重新获取最新的用户数据,用于渲染页面时显示更新后的内容
    
    return render(request, 'changeSelfInfo.html', {
        # 调用 render 函数渲染模板并返回 HTTP 响应
        # 第一个参数 request:当前请求对象
        # 第二个参数 'changeSelfInfo.html':要渲染的模板文件
        # 第三个参数是一个字典,向模板传递数据
        
        'userInfo': userInfo,
        # 将当前用户的完整信息传递给模板
        # 模板中可以通过 {{ userInfo.username }} 显示用户名
        # 通过 {{ userInfo.sex }} 显示性别(如果是 GET 请求,显示原有值)
        # 通过 {{ userInfo.address }} 显示地址
        # 通过 {{ userInfo.avatar }} 显示头像
        # 通过 {{ userInfo.textarea }} 显示个人简介
        
        'nowTime': {
            # 将当前日期信息封装成字典传递给模板
            'year': year,
            # 当前年份,如 2024
            
            'mon': getPublicData.monthList[mon - 1],
            # 当前月份的中文名称
            # mon 是 1-12 的整数
            # getPublicData.monthList 是一个预定义的月份名称列表
            # 列表索引从 0 开始,所以需要 mon - 1
            # 例如 mon=5 时,monthList[4] 得到 'May'
            
            'day': day
            # 当前日期(一个月中的第几天)
        },
    })

四、数据表格tableData 和 添加评论addComments

python 复制代码
def tableData(request):
    # 定义景点数据表格视图函数
    # 这个函数用于展示所有景点的数据表格页面
    # 参数 request 包含当前HTTP请求的所有信息
    
    username = request.session.get('username')
    # 从 session 会话中获取当前登录用户的用户名
    # 这是在用户登录时存储在 session 中的,用于识别当前用户
    
    userInfo = User.objects.get(username=username)
    # 根据用户名从数据库 User 表中查询该用户的完整信息
    # 包含用户名、性别、地址、头像等,用于页面顶部显示用户信息
    
    year, mon, day = getHomeData.getNowTime()
    # 调用 getHomeData 模块中的 getNowTime 函数获取当前日期
    # 返回年、月、日三个整数值,用于页面显示当前时间
    
    talbeData = getPublicData.getAllTravelInfoMapData()
    # 调用 getPublicData 模块中的 getAllTravelInfoMapData 函数
    # 获取所有景点的完整数据,返回经过处理的景点对象列表
    # 注意变量名拼写:talbeData 应该是 tableData
    
    return render(request, 'tableData.html', {
        # 调用 render 函数渲染模板并返回 HTTP 响应
        # 第一个参数 request:当前请求对象
        # 第二个参数 'tableData.html':要渲染的模板文件
        # 第三个参数是字典,向模板传递数据
        
        'userInfo': userInfo,
        # 将当前用户信息传递给模板,用于显示用户名和头像
        
        'nowTime': {
            # 将当前日期信息封装成字典传递给模板
            'year': year,
            'mon': getPublicData.monthList[mon - 1],
            # 将数字月份转换为英文月份名称
            'day': day
        },
        
        'talbeData': talbeData
        # 将所有景点数据传递给模板
        # 模板中通过循环遍历这个列表,生成表格的每一行
        # 显示每个景点的标题、等级、省份、评分、价格等信息
    })

# ============================================================================

def addComments(request, id):
    # 定义添加评论的视图函数
    # 这个函数用于处理用户给景点添加评论的请求
    # 参数 request:当前HTTP请求
    # 参数 id:从URL中捕获的景点ID,如访问 /addComments/123 时,id=123
    # URL配置中的 <int:id> 会将路径中的数字作为id参数传递给这个函数
    
    username = request.session.get('username')
    # 从 session 中获取当前登录用户的用户名
    
    userInfo = User.objects.get(username=username)
    # 根据用户名查询当前用户的完整信息
    
    year, mon, day = getHomeData.getNowTime()
    # 获取当前日期,用于页面显示
    
    travelInfo = getAddCommentsData.getTravelById(id)
    # 调用 getAddCommentsData 模块中的 getTravelById 函数
    # 根据传入的景点ID,从数据库查询该景点的信息
    # 用于在评论页面显示景点名称、图片等
    
    if request.method == 'POST':
        # 判断请求方法是否为 POST
        # GET 请求:用户访问评论页面,显示评论表单
        # POST 请求:用户提交评论表单,需要处理评论保存
        
        getAddCommentsData.addComments({
            # 调用 getAddCommentsData 模块中的 addComments 函数
            # 传入一个字典参数,包含评论所需的所有信息
            'id': id,
            # 景点ID,标识是对哪个景点进行评论
            
            'rate': int(request.POST.get('rate')),
            # 从 POST 数据中获取评分值
            # request.POST.get('rate') 获取表单中 name="rate" 字段的值
            # int() 将字符串转换为整数,因为表单提交的都是字符串
            # 评分通常是 1-5 的整数
            
            'content': request.POST.get('content'),
            # 从 POST 数据中获取评论内容
            # 这是用户填写的评论文本
            
            'userInfo': userInfo,
            # 当前用户的信息,用于记录是谁发表的评论
            
            'travelInfo': travelInfo
            # 当前景点的信息,用于记录是对哪个景点发表的评论
        })
        
        return redirect('/app/tableData')
        # 评论保存成功后,重定向到数据表格页面
        # 让用户返回景点列表,可以看到刚评论的景点
        
    return render(request, 'addComments.html', {
        # 如果是 GET 请求,渲染评论表单页面
        # 如果是 POST 请求且验证失败(虽然代码中没有验证失败的情况),也会渲染表单
        
        'userInfo': userInfo,
        # 将当前用户信息传递给模板
        
        'nowTime': {
            'year': year,
            'mon': getPublicData.monthList[mon - 1],
            'day': day
        },
        # 将当前日期传递给模板
        
        'travelInfo': travelInfo,
        # 将景点信息传递给模板,用于显示要评论的是哪个景点
        
        'id': id
        # 将景点ID传递给模板
        # 可能在表单中作为隐藏字段,或者在URL中保持
    })

函数功能总结

函数 请求方式 功能 数据流向
tableData GET 显示所有景点的数据表格 从数据库获取所有景点,渲染到表格页面
addComments GET 显示评论表单 根据ID获取景点信息,显示评论页面
addComments POST 处理评论提交 接收评分和评论内容,保存到数据库,重定向回表格页

这两个函数共同实现了景点数据展示用户评论功能,让用户可以浏览所有景点并为感兴趣的景点添加评论。

景点数据表格功能

tableData函数 负责展示所有景点的数据表格页面。当用户访问这个页面时,函数首先从会话中获取当前登录用户的用户名,然后查询该用户的完整信息用于页面顶部显示。接着获取当前日期,并调用公共数据模块的函数获取所有景点的完整数据。最后将这些数据打包传递给tableData.html模板进行渲染。

最终呈现给用户的是一个包含所有景点信息的表格,每行显示一个景点的标题、等级、省份、评分、价格等字段,用户可以在表格中浏览所有景点数据。

添加评论功能

addComments函数处理用户给景点添加评论的请求,支持两种请求方式:

当用户通过GET请求访问评论页面时(如点击某个景点的"添加评论"按钮),函数会从会话中获取当前用户信息,从URL参数中获取景点ID,根据这个ID查询该景点的详细信息,然后将用户信息、景点信息、当前日期传递给addComments.html模板,渲染出一个评论表单页面。页面上会显示景点名称等信息,并提供评分选择(通常是1-5星)和评论内容输入框。

当用户在表单中填写完评分和评论内容并点击提交后,浏览器发送POST请求。函数接收到POST请求后,从请求数据中提取评分和评论内容,连同用户信息、景点信息一起打包,调用专门的处理函数将这些数据保存到数据库中。保存成功后,页面自动重定向回数据表格页面,让用户可以继续浏览其他景点。

两个功能的关联

这两个功能是紧密联系的:用户在数据表格页面浏览景点时,可以为感兴趣的景点点击"添加评论"按钮,跳转到评论页面;评论提交后又会返回表格页面。这样形成了一个完整的功能闭环,让用户既能浏览信息,又能参与互动。

添加评论getAddCommentsData.py

python 复制代码
from app.models import TravelInfo
# 从当前项目的 app 应用中导入 TravelInfo 模型类
# 
# app:这是您自己创建的 Django 应用名称,在 INSTALLED_APPS 中注册过
# models:这是 Django 应用中默认存放模型定义的文件(models.py)
# TravelInfo:这是在 models.py 中定义的模型类,对应数据库中的景点信息表
#
# 导入后,就可以在代码中使用 TravelInfo 类来操作数据库中的景点数据
# 例如:TravelInfo.objects.all() 查询所有景点
#       TravelInfo.objects.create() 创建新景点记录

from app.utils.getHomeData import getNowTime
# 从 app 应用的 utils 包中的 getHomeData 模块导入 getNowTime 函数
#
# app:当前 Django 应用
# utils:这是一个自定义的 Python 包,通常用于存放工具函数
#       在项目中应该有一个 utils 文件夹,里面包含 __init__.py 文件
# getHomeData:这是 utils 包中的一个 Python 模块文件(getHomeData.py)
# getNowTime:这是在 getHomeData.py 中定义的一个函数,用于获取当前时间
#
# 导入后,可以直接调用 getNowTime() 函数来获取当前的年、月、日信息
# 这个函数在多个视图函数中都被使用,所以被抽取到公共模块中

import json
# 导入 Python 标准库中的 json 模块
# json 是 Python 内置的库,不需要额外安装
#
# json 模块提供了处理 JSON 数据格式的功能:
#   - json.loads():将 JSON 字符串解析为 Python 对象(列表、字典)
#   - json.dumps():将 Python 对象转换为 JSON 字符串
#
# 在项目中,景点表中的 img_list 和 comments 字段是以 JSON 字符串形式存储的
# 从数据库读取时需要解析为 Python 对象才能使用
# 将数据存入数据库时需要将 Python 对象转换为 JSON 字符串

from app.models import TravelInfo
# 从 app 应用的 models 模块中导入 TravelInfo 模型类
# TravelInfo 对应数据库中的景点信息表,包含景点的所有信息

from app.utils.getHomeData import getNowTime
# 从 app 应用的 utils 包中的 getHomeData 模块导入 getNowTime 函数
# getNowTime 函数用于获取当前的年、月、日信息

import json
# 导入 Python 的 json 模块,用于处理 JSON 数据的序列化和反序列化
# 景点表中的 img_list 和 comments 字段都是以 JSON 字符串格式存储的

def getTravelById(id):
    # 定义根据景点 ID 获取景点信息的函数
    # 参数 id:要查询的景点的主键 ID
    
    travel = TravelInfo.objects.get(id=id)
    # 使用 Django ORM 的 get 方法从数据库中查询主键 ID 等于传入 id 的景点记录
    # get 方法返回满足条件的唯一一条记录,如果不存在或存在多条会抛出异常
    
    travel.img_list = json.loads(travel.img_list)
    # 将景点对象中的 img_list 字段从 JSON 字符串解析为 Python 列表
    # travel.img_list 原本是从数据库取出的 JSON 字符串,如 '["url1.jpg","url2.jpg"]'
    # json.loads() 将其转换为 Python 列表,如 ['url1.jpg', 'url2.jpg']
    # 这样在代码中就可以方便地遍历和操作图片列表
    
    travel.comments = json.loads(travel.comments)
    # 同样,将 comments 字段从 JSON 字符串解析为 Python 列表
    # comments 字段存储的是该景点的所有用户评论,每个评论是一个字典
    # 解析后变成 [{'author':'张三', 'content':'很好', ...}, ...] 格式
    
    return travel
    # 返回处理后的景点对象,此时 img_list 和 comments 已经是 Python 列表
    # 调用者可以直接使用这些列表数据

def addComments(commentData):
    # 定义添加评论的函数,处理用户提交的评论数据
    # 参数 commentData 是一个字典,包含了评论所需的所有信息
    # 这个字典由视图函数 addComments 在 POST 请求处理时构建并传入
    
    # 函数开头的注释说明了评论数据的结构
    # 'author': author,          # 评论作者(这个字段实际被下面的 username 替代了)
    # 'content': content,        # 评论内容
    # 'date': date,              # 评论日期
    # 'score': score             # 评分
    # authorId                   # 作者ID(注释中有但实际没用到?)
    
    year, month, day = getNowTime()
    # 调用 getNowTime 函数获取当前的年、月、日
    # 用于生成评论的日期,格式如 '2024-03-19'
    
    travelInfo = commentData['travelInfo']
    # 从 commentData 字典中获取景点信息对象
    # travelInfo 是调用 getTravelById 获取的景点对象,此时它的 comments 已经是 Python 列表
    
    travelInfo.comments.append({
        # 向景点的评论列表中添加一条新评论
        # travelInfo.comments 是一个列表,append 方法向列表末尾添加新元素
        
        'author': commentData['userInfo'].username,
        # 从 commentData 中获取用户信息对象,再获取其 username 属性
        # 这是发表评论的用户名
        
        'score': commentData['rate'],
        # 从 commentData 中获取评分值(rate)
        # 这是用户给景点的打分,通常是 1-5 的整数
        
        'content': commentData['content'],
        # 从 commentData 中获取评论内容
        # 这是用户填写的评论文本
        
        'date': str(year) + '-' + str(month) + '-' + str(day),
        # 拼接当前日期,格式为 "年-月-日"
        # 将年、月、日三个整数转换为字符串并用短横线连接
        
        'userId': commentData['userInfo'].id,
        # 从 commentData 中获取用户信息对象,再获取其 id 属性
        # 这是发表评论的用户ID,可用于后续查询该用户的所有评论
    })
    
    travelInfo.comments = json.dumps(travelInfo.comments)
    # 将更新后的评论列表(现在是 Python 列表)转换回 JSON 字符串
    # json.dumps() 执行序列化,如将 [{'author':'张三',...}] 转换为 JSON 字符串
    # 因为数据库中的 comments 字段存储的是 JSON 字符串,不是 Python 列表
    
    travelInfo.img_list = json.dumps(travelInfo.img_list)
    # 同样,将图片列表也转换回 JSON 字符串
    # 虽然这次操作没有修改图片列表,但为了保持数据一致性也进行了序列化
    # 确保存入数据库时所有字段都是正确的格式
    
    travelInfo.save()
    # 调用 Django ORM 的 save 方法,将更新后的景点对象保存回数据库
    # save() 方法会自动生成 UPDATE SQL 语句,更新数据库中的对应记录
    # 此时,新添加的评论就永久保存到数据库中了

函数功能总结

函数 输入 输出 主要功能
getTravelById 景点ID 景点对象 根据ID查询景点,并将JSON字段解析为Python列表
addComments 评论数据字典 无返回值 将新评论添加到景点评论列表,并保存回数据库

这两个函数配合工作:getTravelById负责从数据库读取并解析数据,addComments负责将用户提交的评论整合到景点数据中并写回数据库,共同实现了评论功能的完整数据操作。

五、

python 复制代码
def cityChar(request):
    # 定义城市景点分析图表视图函数
    # 这个函数处理城市景点分布和等级分布图表的请求
    
    username = request.session.get('username')
    # 从 session 会话中获取当前登录用户的用户名
    
    userInfo = User.objects.get(username=username)
    # 根据用户名从数据库 User 表中查询该用户的完整信息
    
    year, mon, day = getHomeData.getNowTime()
    # 调用 getHomeData 模块中的 getNowTime 函数获取当前日期
    
    Xdata, Ydata = getEchartsData.cityCharDataOne()
    # 调用 getEchartsData 模块中的 cityCharDataOne 函数
    # 获取城市景点分布数据(按省份统计)
    # Xdata: 省份名称列表
    # Ydata: 对应省份的景点数量列表
    
    resultData = getEchartsData.cityCharDataTwo()
    # 调用 getEchartsData 模块中的 cityCharDataTwo 函数
    # 获取景点等级分布数据(按5A、4A等统计)
    # resultData: 包含等级名称和数量的字典列表
    
    return render(request, 'cityChar.html', {
        # 渲染 cityChar.html 模板并返回响应
        'userInfo': userInfo,
        # 传递用户信息到模板
        
        'nowTime': {
            'year': year,
            'mon': getPublicData.monthList[mon - 1],
            'day': day
        },
        # 传递当前日期到模板,用于页面顶部显示
        
        'cityCharOneData': {
            'Xdata': Xdata,
            'Ydata': Ydata
        },
        # 传递城市景点分布数据到模板
        # 用于生成柱状图或饼图,展示各省份景点数量
        
        'cityCharTwoData': resultData
        # 传递景点等级分布数据到模板
        # 用于生成饼图,展示各等级景点占比
    })

# ============================================================================

def rateChar(request):
    # 定义评分分析图表视图函数
    # 这个函数处理景点评分分布图表的请求,支持按城市筛选
    
    username = request.session.get('username')
    # 获取当前登录用户用户名
    
    userInfo = User.objects.get(username=username)
    # 获取当前用户完整信息
    
    year, mon, day = getHomeData.getNowTime()
    # 获取当前日期
    
    cityList = getPublicData.getCityList()
    # 调用 getPublicData 模块中的 getCityList 函数
    # 获取所有有景点数据的城市列表,用于下拉框
    
    travelList = getPublicData.getAllTravelInfoMapData(cityList[0])
    # 默认选择第一个城市,获取该城市的所有景点数据
    # getAllTravelInfoMapData 函数会处理 JSON 字段
    
    charOneData = getEchartsData.getRateCharDataOne(travelList)
    # 调用 getEchartsData 模块中的 getRateCharDataOne 函数
    # 获取星级分布数据(基于 travel.star 字段)
    # 返回包含星级名称和数量的字典列表
    
    charTwoData = getEchartsData.getRateCharDataTwo(travelList)
    # 调用 getEchartsData 模块中的 getRateCharDataTwo 函数
    # 获取分数分布数据(基于 travel.score 字段)
    # 返回包含分数和数量的字典列表
    
    if request.method == 'POST':
        # 判断请求方法是否为 POST
        # 用户通过下拉框选择城市并提交表单时会触发 POST 请求
        
        travelList = getPublicData.getAllTravelInfoMapData(request.POST.get('province'))
        # 从 POST 数据中获取用户选择的省份
        # 调用 getAllTravelInfoMapData 函数获取该省份的所有景点数据
        
        charOneData = getEchartsData.getRateCharDataOne(travelList)
        # 重新获取该省份的星级分布数据
        
        charTwoData = getEchartsData.getRateCharDataTwo(travelList)
        # 重新获取该省份的分数分布数据

    return render(request, 'rateChar.html', {
        # 渲染 rateChar.html 模板并返回响应
        
        'userInfo': userInfo,
        # 传递用户信息
        
        'nowTime': {
            'year': year,
            'mon': getPublicData.monthList[mon - 1],
            'day': day
        },
        # 传递当前日期
        
        'cityList': cityList,
        # 传递城市列表到模板,用于生成下拉选择框
        
        'charOneData': charOneData,
        # 传递星级分布数据到模板
        # 用于生成饼图或柱状图
        
        'charTwoData': charTwoData
        # 传递分数分布数据到模板
        # 用于生成另一个饼图或柱状图
    })

# ============================================================================

def priceChar(request):
    # 定义价格销量分析图表视图函数
    # 这个函数处理价格分布、销量分布和折扣分布图表的请求
    
    username = request.session.get('username')
    # 获取当前登录用户用户名
    
    userInfo = User.objects.get(username=username)
    # 获取当前用户完整信息
    
    year, mon, day = getHomeData.getNowTime()
    # 获取当前日期
    
    cityList = getPublicData.getCityList()
    # 获取所有有景点数据的城市列表
    
    travelList = getPublicData.getAllTravelInfoMapData()
    # 获取所有城市的景点数据(全国数据)
    
    xData, yData = getEchartsData.getPriceCharDataOne(travelList)
    # 调用 getEchartsData 模块中的 getPriceCharDataOne 函数
    # 获取价格分布数据
    # xData: 价格区间列表,如 ['免费','100元以内',...]
    # yData: 对应各区间的景点数量列表
    
    x1Data, y1Data = getEchartsData.getPriceCharDataTwo(travelList)
    # 调用 getEchartsData 模块中的 getPriceCharDataTwo 函数
    # 获取销量分布数据
    # x1Data: 销量区间列表,如 ['300份以内','600份以内',...]
    # y1Data: 对应各区间的景点数量列表
    
    disCountPieData = getEchartsData.getPriceCharDataThree(travelList)
    # 调用 getEchartsData 模块中的 getPriceCharDataThree 函数
    # 获取折扣分布数据
    # disCountPieData: 包含折扣类型和数量的字典列表
    
    return render(request, 'priceChar.html', {
        # 渲染 priceChar.html 模板并返回响应
        
        'userInfo': userInfo,
        # 传递用户信息
        
        'nowTime': {
            'year': year,
            'mon': getPublicData.monthList[mon - 1],
            'day': day
        },
        # 传递当前日期
        
        'cityList': cityList,
        # 传递城市列表到模板(虽然当前代码中 priceChar.html 可能没有使用城市筛选)
        
        'echartsData': {
            # 将所有图表数据封装在一个字典中传递给模板
            
            'xData': xData,
            # 价格分布横坐标数据
            
            'yData': yData,
            # 价格分布纵坐标数据
            
            'x1Data': x1Data,
            # 销量分布横坐标数据
            
            'y1Data': y1Data,
            # 销量分布纵坐标数据
            
            'disCountPieData': disCountPieData
            # 折扣分布饼图数据
        }
    })

# ============================================================================

def commentsChar(request):
    # 定义评论分析图表视图函数
    # 这个函数处理评论时间分布、评论评分分布和评论数量分布图表的请求
    
    username = request.session.get('username')
    # 获取当前登录用户用户名
    
    userInfo = User.objects.get(username=username)
    # 获取当前用户完整信息
    
    year, mon, day = getHomeData.getNowTime()
    # 获取当前日期
    
    xData, yData = getEchartsData.getCommentsCharDataOne()
    # 调用 getEchartsData 模块中的 getCommentsCharDataOne 函数
    # 获取评论时间分布数据(折线图用)
    # xData: 日期列表,按倒序排列
    # yData: 对应日期的评论数量列表
    
    commentsScorePieData = getEchartsData.getCommentsCharDataTwo()
    # 调用 getEchartsData 模块中的 getCommentsCharDataTwo 函数
    # 获取评论评分分布数据(饼图用)
    # commentsScorePieData: 包含评分和数量的字典列表
    
    x1Data, y1Data = getEchartsData.getCommentsCharDataThree()
    # 调用 getEchartsData 模块中的 getCommentsCharDataThree 函数
    # 获取评论数量分布数据(柱状图用)
    # x1Data: 评论条数区间列表,如 ['1000条以内','2000条以内',...]
    # y1Data: 对应各区间的景点数量列表
    
    return render(request, 'commentsChar.html', {
        # 渲染 commentsChar.html 模板并返回响应
        
        'userInfo': userInfo,
        # 传递用户信息
        
        'nowTime': {
            'year': year,
            'mon': getPublicData.monthList[mon - 1],
            'day': day
        },
        # 传递当前日期
        
        'echartsData': {
            # 将所有图表数据封装在一个字典中传递给模板
            
            'xData': xData,
            # 评论时间分布横坐标数据
            
            'yData': yData,
            # 评论时间分布纵坐标数据
            
            'commentsScorePieData': commentsScorePieData,
            # 评论评分分布饼图数据
            
            'x1Data': x1Data,
            # 评论数量分布横坐标数据(柱状图)
            
            'y1Data': y1Data
            # 评论数量分布纵坐标数据(柱状图)
        }
    })

# ============================================================================

def recommendation(request):
    # 定义推荐页面视图函数
    # 这个函数处理个性化推荐,调用协同过滤算法为用户生成推荐列表
    
    username = request.session.get('username')
    # 获取当前登录用户用户名
    
    userInfo = User.objects.get(username=username)
    # 获取当前用户完整信息
    
    year, mon, day = getHomeData.getNowTime()
    # 获取当前日期
    
    try:
        # 尝试执行推荐算法
        # 如果成功,返回个性化推荐结果
        
        user_ratings = getUser_ratings()
        # 调用函数获取用户的评分数据
        # 这里假设有一个 getUser_ratings 函数可以获取用户的历史评分
        
        recommended_items = user_bases_collaborative_filtering(userInfo.id, user_ratings)
        # 调用基于用户的协同过滤算法
        # 传入当前用户ID和所有用户的评分数据
        # 算法返回推荐的景点ID列表
        
        resultDataList = getRecommendationData.getAllTravelByTitle(recommended_items)
        # 根据推荐的景点ID列表,从数据库获取完整的景点信息
        # 返回景点对象列表,用于页面展示
        
    except:
        # 如果推荐算法执行失败(如用户没有历史数据、算法异常等)
        
        resultDataList = getRecommendationData.getRandomTravel()
        # 调用备用函数,随机获取一些景点作为推荐
        # 这是冷启动问题的简单处理方案

    return render(request, 'recommendation.html', {
        # 渲染 recommendation.html 模板并返回响应
        
        'userInfo': userInfo,
        # 传递用户信息
        
        'nowTime': {
            'year': year,
            'mon': getPublicData.monthList[mon - 1],
            'day': day
        },
        # 传递当前日期
        
        'resultDataList': resultDataList
        # 传递推荐结果列表到模板
        # 模板中通过循环遍历展示每个推荐的景点
    })

# ============================================================================

def detailIntroCloud(request):
    # 定义景点介绍词云图页面视图函数
    # 这个函数渲染景点介绍词云图页面
    
    username = request.session.get('username')
    # 获取当前登录用户用户名
    
    userInfo = User.objects.get(username=username)
    # 获取当前用户完整信息
    
    year, mon, day = getHomeData.getNowTime()
    # 获取当前日期
    
    return render(request, 'detailIntroCloud.html', {
        # 渲染 detailIntroCloud.html 模板并返回响应
        
        'userInfo': userInfo,
        # 传递用户信息
        
        'nowTime': {
            'year': year,
            'mon': getPublicData.monthList[mon - 1],
            'day': day
        }
        # 传递当前日期
        # 词云图的数据可能在前端通过 Ajax 获取,或者后端通过其他方式传递
    })

# ============================================================================

def commentContentCloud(request):
    # 定义评论内容词云图页面视图函数
    # 这个函数渲染评论内容词云图页面
    # 注意:这个函数中有重复代码和未使用的变量
    
    username = request.session.get('username')
    # 获取当前登录用户用户名
    
    userInfo = User.objects.get(username=username)
    # 获取当前用户完整信息

    a5Len, commentsLenTitle, provienceDicSort = getHomeData.getHomeTagData()
    # 获取首页标签数据
    # a5Len: 5A级景区数量
    # commentsLenTitle: 评论最多的景区名称
    # provienceDicSort: 分布最多的省份
    # 这些变量在当前函数中可能没有使用

    scoreTop100Data, saleCountTop100 = getHomeData.getAnthorData2()
    # 获取评分和销量最高的数据(各300条)
    # scoreTop100Data: 随机选取的300个满分景点
    # saleCountTop100: 销量最高的300个景点
    # 这些变量在当前函数中可能没有使用

    year, mon, day = getHomeData.getNowTime()
    # 获取当前日期

    geoData = getHomeData.getGeoData()
    # 获取地理分布数据
    # 这个变量在当前函数中可能没有使用

    userBarCharData = getHomeData.getUserCreateTimeData()
    # 获取用户创建时间分布数据
    # 这个变量在当前函数中可能没有使用

    return render(request, 'commentContentCloud.html', {
        # 第一次渲染 commentContentCloud.html 模板
        # 注意:下面传递了很多可能不需要的数据
        
        'userInfo': userInfo,
        # 传递用户信息
        
        'a5Len': a5Len,
        # 传递5A景区数量(可能不需要)
        
        'commentsLenTitle': commentsLenTitle,
        # 传递评论最多的景区名称(可能不需要)
        
        'provienceDicSort': provienceDicSort,
        # 传递分布最多的省份(可能不需要)
        
        'scoreTop10Data': scoreTop100Data,
        # 传递评分最高的300个景点(变量名是Top10但实际是300)
        
        'nowTime': {
            'year': year,
            'mon': getPublicData.monthList[mon - 1],
            'day': day
        },
        # 传递当前日期
        
        'geoData': geoData,
        # 传递地理分布数据(可能不需要)
        
        'userBarCharData': userBarCharData,
        # 传递用户创建时间分布数据(可能不需要)
        
        'saleCountTop10': saleCountTop100
        # 传递销量最高的300个景点(变量名是Top10但实际是300)
    })

    # 注意:下面的代码永远不会被执行,因为上面已经有 return 了
    year, mon, day = getHomeData.getNowTime()
    # 再次获取当前日期(重复代码)
    
    return render(request, 'commentContentCloud.html', {
        # 第二次渲染同一个模板(永远不会执行)
        'userInfo': userInfo,
        'nowTime': {
            'year': year,
            'mon': getPublicData.monthList[mon - 1],
            'day': day
        }
    })
相关推荐
qq_417695051 小时前
机器学习与人工智能
jvm·数据库·python
ego.iblacat2 小时前
MySQL 服务基础
数据库·mysql
yy我不解释2 小时前
关于comfyui的mmaudio音频生成插件时时间不一致问题(一)
python·ai作画·音视频·comfyui
踩着两条虫3 小时前
VTJ.PRO 核心架构全公开!从设计稿到代码,揭秘AI智能体如何“听懂人话”
前端·vue.js·ai编程
Maverick063 小时前
Oracle Redo 日志操作手册
数据库·oracle
紫丁香3 小时前
AutoGen详解一
后端·python·flask
FreakStudio4 小时前
不用费劲编译ulab了!纯Mpy矩阵micronumpy库,单片机直接跑
python·嵌入式·边缘计算·电子diy
攒了一袋星辰4 小时前
高并发强一致性顺序号生成系统 -- SequenceGenerator
java·数据库·mysql
jzlhll1234 小时前
kotlin Flow first() last()总结
开发语言·前端·kotlin