Django+MySQL图片推荐系统毕设实战:环境搭建、ORM设计与简易推荐算法
简介这份资源是面向计算机专业大学生、研究生及Web开发爱好者的毕业设计完整文档围绕基于Django框架与MySQL数据库的图片推荐系统展开帮助读者理解从需求分析到系统测试的全流程开发思路。压缩包内仅含1个docx文件约3.75MB内容涵盖系统需求分析、功能模块设计、数据库设计、详细实现与测试维护等章节并配有中英文摘要与目录结构便于直接参考论文写作框架与设计表达。目前已有53人学习浏览。读者可从中获取完整的选题背景论述、Python与Django技术选型说明、MySQL数据存储方案以及用户管理、图片信息管理、信息共享等核心模块的设计细节适合作为同类Web推荐系统课题的参考模板与写作范例。1. 从一份毕设源码说起Django MySQL 图片推荐系统能跑出什么很多同学拿到“基于Django框架和MySQL的图片推荐系统设计与实现”这类毕设资源时第一反应是“能不能直接跑起来”。我拆过不少类似的项目包说实话这类资源的核心价值不在于推荐算法有多深而在于它是一套完整的、能跑通的 Web 工程闭环Python 语言做后端逻辑Django 框架负责路由、ORM 和模板渲染MySQL 数据库存用户、图片、评论、资讯这些实体数据B/S 架构让浏览器直接访问不需要装客户端。它解决的是“从零搭一个图片管理加推荐展示平台”的问题适合计算机专业做毕设的学生、刚接触 Django 想找一个完整项目练手的开发者以及需要快速验证图片类 Web 应用原型的从业者。你拿到手之后重点不是看它推荐多准而是看它怎么把用户管理、图片信息管理、地区管理、系统管理这几个模块串起来以及数据库表是怎么设计的。2. 环境搭建与项目初始化Python 3.6.4 Django MySQL 的版本对齐2.1 为什么版本对齐是第一个坎这份资源里明确写了开发环境用的是 Python 3.6.4Django 框架MySQL 数据库。很多新手上来就装最新版 Python 3.12然后 pip install django 直接拉最新版结果跑 migrate 的时候报一堆编码错误和依赖冲突。这不是玄学是 Django 不同版本对 MySQL 驱动和 Python 版本的支持矩阵不一样。我一般会先确认三件事Python 版本、Django 版本、MySQL 驱动版本。资源里没写具体 Django 版本号但根据 Python 3.6.4 这个时间点常见搭配是 Django 2.x 系列MySQL 驱动用 mysqlclient 或者 pymysql。如果你不想折腾编译pymysql 是更省事的选择纯 Python 实现装完在init.py 里补两行就行。2.2 虚拟环境与依赖安装先建虚拟环境别把系统 Python 搞乱。这一步是血泪经验我见过太多人因为全局装包导致后面版本冲突最后只能重装系统。# 创建虚拟环境指定 Python 3.6.4 路径 python3.6 -m venv venv # 激活虚拟环境Linux/macOS source venv/bin/activate # 激活虚拟环境Windows venv\Scripts\activate # 安装 Django根据资源年代选 2.2 LTS 版本 pip install django2.2.28 # 安装 MySQL 驱动pymysql 纯 Python 实现免编译 pip install pymysql # 安装图片处理库Django 的 ImageField 依赖 Pillow pip install Pillow逻辑说明venv 隔离环境避免污染全局Django 2.2 是 LTS 版本对 Python 3.6 支持稳定pymysql 替代 mysqlclient 可以绕过本地 MySQL 开发库的编译依赖Pillow 是图片字段必须的不装的话模型迁移会直接报错。参数说明django2.2.28 是 2.2 系列最后一个安全维护版本兼容性最好。如果你拿到手的资源里 requirements.txt 写了别的版本以资源为准但 Python 3.6.4 这个底线别动。2.3 MySQL 数据库创建与 Django 配置数据库这块资源里说了用 MySQL但没给建库语句。我一般会手动建一个库字符集用 utf8mb4不然存中文图片标题和评论会出乱码。-- 创建数据库字符集 utf8mb4 支持完整 Unicode CREATE DATABASE image_recommend DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 创建一个专用用户别直接用 root CREATE USER img_userlocalhost IDENTIFIED BY Img2024Pass; -- 授权该用户对 image_recommend 库的所有权限 GRANT ALL PRIVILEGES ON image_recommend.* TO img_userlocalhost; -- 刷新权限 FLUSH PRIVILEGES;然后改 Django 的 settings.py找到 DATABASES 配置段# settings.py 数据库配置 DATABASES { default: { ENGINE: django.db.backends.mysql, # 使用 MySQL 后端 NAME: image_recommend, # 数据库名 USER: img_user, # 专用用户 PASSWORD: Img2024Pass, # 密码 HOST: 127.0.0.1, # 本机 PORT: 3306, # 默认端口 OPTIONS: { charset: utf8mb4, # 字符集对齐 init_command: SET sql_modeSTRICT_TRANS_TABLES, # 严格模式 }, } }逻辑说明ENGINE 指定 MySQL 后端OPTIONS 里的 charset 必须和建库时一致init_command 设置严格模式避免数据截断不报错。改完 settings.py 之后还要在项目根目录的init.py 里加两行让 Django 用 pymysql 替代默认驱动# __init__.py 驱动替换 import pymysql pymysql.install_as_MySQLdb()这两行不加migrate 的时候会报 “Error loading MySQLdb module”。这是最常见的翻车点之一。2.4 迁移与超级用户创建配置完数据库执行迁移命令。资源里数据库表设计部分提到了用户表、图片信息表、新闻资讯表、评论表这些在 Django 的 models.py 里应该都有对应定义。# 生成迁移文件 python manage.py makemigrations # 执行迁移建表 python manage.py migrate # 创建后台超级管理员 python manage.py createsuperuser逻辑说明makemigrations 根据 models.py 生成 SQL 迁移脚本migrate 真正在 MySQL 里建表createsuperuser 创建后台登录账号用于管理用户、图片、地区等数据。如果 migrate 报错先看数据库连接是否通再看 models.py 里有没有字段类型和 MySQL 不兼容的比如 TextField 默认长度问题。3. 核心模块拆解用户、图片、评论三张表的 ORM 设计与联调3.1 用户模块从注册到权限分流资源里登录流程图写得很清楚输入账号密码验证通过后判断账号类型再进入不同后台。这个逻辑在 Django 里通常用自定义用户模型或者 Profile 扩展来实现。我一般会先看 models.py 里用户表是怎么定义的。如果资源用的是 Django 内置 User 模型加 Profile 扩展那核心字段就是用户名、密码、手机、姓名、头像、年龄、性别、地区。地区管理单独一个表用户表用外键关联。# models.py 用户扩展模型示例 from django.contrib.auth.models import User from django.db import models class UserProfile(models.Model): user models.OneToOneField(User, on_deletemodels.CASCADE, related_nameprofile) phone models.CharField(max_length20, blankTrue, verbose_name手机) real_name models.CharField(max_length50, blankTrue, verbose_name姓名) avatar models.ImageField(upload_toavatars/, blankTrue, verbose_name头像) age models.IntegerField(nullTrue, blankTrue, verbose_name年龄) gender models.CharField(max_length10, choices[(male,男),(female,女)], blankTrue) region models.ForeignKey(Region, on_deletemodels.SET_NULL, nullTrue, verbose_name地区) class Meta: db_table user_profile verbose_name 用户信息逻辑说明OneToOneField 和内置 User 一对一绑定不破坏 Django 认证体系avatar 用 ImageField需要 Pillow 支持region 外键关联地区表on_delete 用 SET_NULL地区删了用户还在。参数说明upload_to 指定头像存储子目录实际文件落在 MEDIA_ROOT 下db_table 自定义表名方便和资源里的数据库表设计对齐。3.2 图片信息模块字段设计与推荐位图片信息表是核心资源里 E/R 图列了版权、来源、大小、标题、图片、尺寸、格式这些属性。实际建表的时候图片文件本身用 ImageField尺寸和格式可以在保存时自动提取不用手动填。# models.py 图片信息模型 class ImageInfo(models.Model): title models.CharField(max_length200, verbose_name标题) image models.ImageField(upload_toimages/%Y/%m/, verbose_name图片) source models.CharField(max_length100, blankTrue, verbose_name来源) copyright models.CharField(max_length100, blankTrue, verbose_name版权) size models.CharField(max_length20, blankTrue, verbose_name大小) dimensions models.CharField(max_length20, blankTrue, verbose_name尺寸) format models.CharField(max_length10, blankTrue, verbose_name格式) is_recommend models.BooleanField(defaultFalse, verbose_name是否推荐) created_at models.DateTimeField(auto_now_addTrue) def save(self, *args, **kwargs): # 保存时自动提取图片元信息 if self.image: self.size f{self.image.size / 1024:.1f} KB from PIL import Image img Image.open(self.image) self.dimensions f{img.width}x{img.height} self.format img.format super().save(*args, **kwargs) class Meta: db_table image_info ordering [-created_at]逻辑说明upload_to 用日期分目录避免单目录文件过多save 方法重写在保存前用 Pillow 读取图片宽高和格式自动填充字段is_recommend 布尔字段控制是否在首页推荐位展示。参数说明size 存的是格式化后的字符串方便模板直接显示ordering 按创建时间倒序最新图片排前面。3.3 评论模块与前后台联调评论表资源里叫“图片信息评论”字段有关联表 id、回复内容、用户 id、评论内容、头像、用户名。实际设计时评论和图片是多对一和用户是多对一。# models.py 评论模型 class Comment(models.Model): image models.ForeignKey(ImageInfo, on_deletemodels.CASCADE, related_namecomments) user models.ForeignKey(User, on_deletemodels.CASCADE) content models.TextField(verbose_name评论内容) reply models.TextField(blankTrue, verbose_name回复内容) created_at models.DateTimeField(auto_now_addTrue) class Meta: db_table image_comment ordering [-created_at]逻辑说明ForeignKey 关联图片和用户on_deleteCASCADE 表示图片删了评论也删reply 字段用于管理员回复related_namecomments 方便反向查询。联调的时候前台模板里用 {% for comment in image.comments.all %} 就能拿到某张图的所有评论。3.4 后台管理注册与前台路由配置Django 自带 admin 后台把模型注册进去就能管理数据。# admin.py 注册模型 from django.contrib import admin from .models import UserProfile, ImageInfo, Comment, Region admin.register(ImageInfo) class ImageInfoAdmin(admin.ModelAdmin): list_display (title, format, dimensions, is_recommend, created_at) list_filter (is_recommend, format) search_fields (title, source) admin.site.register(UserProfile) admin.site.register(Comment) admin.site.register(Region)逻辑说明list_display 控制后台列表显示哪些列list_filter 提供筛选器search_fields 支持搜索。前台路由在 urls.py 里配置首页、图片列表、详情、个人中心各一个视图函数或类视图。4. 避坑与排查从 migrate 报错到图片不显示的五个高频问题4.1 migrate 时报 “Unknown database” 或连接被拒现象执行 python manage.py migrate 直接报错提示数据库不存在或拒绝连接。原因settings.py 里的数据库名、用户、密码和实际 MySQL 里建的不一致或者 MySQL 服务没启动。解决先用 mysql -u img_user -p 手动登录测试确认库和用户权限都对再看 settings.py 的 HOST 是 127.0.0.1 还是 localhost有些环境 localhost 走 socket 不走 TCP改成 127.0.0.1 更稳。4.2 图片上传后前台不显示现象后台上传图片成功数据库里有记录但前台模板里 img 标签的 src 是空的或者 404。原因MEDIA_URL 和 MEDIA_ROOT 没配或者开发环境下没加静态文件服务路由。解决settings.py 里设 MEDIA_URL /media/ 和 MEDIA_ROOT os.path.join(BASE_DIR, media)urls.py 里加 from django.conf.urls.static import static 和 static(settings.MEDIA_URL, document_rootsettings.MEDIA_ROOT)。注意这只在 DEBUGTrue 时有效生产环境要用 Nginx 或类似方案。4.3 中文乱码数据库、连接、模板三处都要对齐现象图片标题或评论存进去是问号或者页面显示乱码。原因MySQL 建库时字符集不是 utf8mb4或者 Django 连接配置里没指定 charset或者模板文件没存成 UTF-8。解决建库用 utf8mb4settings.py 的 OPTIONS 里加 charsetHTML 模板头部加 。三处缺一不可我见过只改两处然后排查半天的。4.4 静态文件 404CSS 和 JS 加载不出来现象页面能打开但样式全丢控制台一堆 404。原因STATIC_URL 和 STATICFILES_DIRS 没配或者 Django 开发服务器没服务静态文件。解决settings.py 里设 STATIC_URL /static/STATICFILES_DIRS 指向项目里的 static 目录确认 INSTALLED_APPS 里有 django.contrib.staticfiles。开发阶段 runserver 会自动服务静态文件但前提是配置对。4.5 推荐位不生效is_recommend 字段查询逻辑写反现象后台勾了“是否推荐”但首页推荐区还是空的。原因视图里查询条件写成了 filter(is_recommendFalse)或者模板里判断逻辑反了。解决检查 views.py 里首页视图的查询应该是 ImageInfo.objects.filter(is_recommendTrue)[:8] 这种模板里用 {% if image.is_recommend %} 判断。这种问题属于逻辑翻车不是环境问题但排查起来一样费时间。5. 进阶技巧用 Django ORM 做简易协同过滤推荐与数据验证5.1 不引入额外依赖的 Item-CF 思路资源本身没有实现复杂推荐算法但既然叫图片推荐系统总得有个推荐逻辑。我一般会在不引入 surprise、scikit-learn 这些重依赖的前提下用 Django ORM 加 Python 原生字典做一个简易的 Item-CF。核心思路是基于用户对图片的评论行为计算图片之间的相似度然后给用户推荐他没看过但相似图片里热门的。# views.py 简易 Item-CF 推荐函数 from collections import defaultdict from .models import Comment, ImageInfo def recommend_for_user(user, top_n8): # 1. 拿到当前用户评论过的图片 id 集合 user_images set(Comment.objects.filter(useruser).values_list(image_id, flatTrue)) if not user_images: # 没有行为数据退化为热门推荐 return ImageInfo.objects.filter(is_recommendTrue)[:top_n] # 2. 构建图片-用户倒排表 image_users defaultdict(set) for c in Comment.objects.all().values(image_id, user_id): image_users[c[image_id]].add(c[user_id]) # 3. 计算相似度共同评论用户数 / 并集用户数 sim_scores defaultdict(float) for img_id in user_images: for other_id, users in image_users.items(): if other_id img_id: continue common image_users[img_id] users union image_users[img_id] | users if union: sim_scores[other_id] len(common) / len(union) # 4. 按相似度排序排除已看过的 ranked sorted(sim_scores.items(), keylambda x: x[1], reverseTrue) recommended_ids [img_id for img_id, _ in ranked if img_id not in user_images][:top_n] # 5. 按推荐 id 顺序返回图片对象 images ImageInfo.objects.filter(id__inrecommended_ids) image_map {img.id: img for img in images} return [image_map[i] for i in recommended_ids if i in image_map]逻辑说明第一步拿用户行为第二步构建倒排索引避免每次循环查数据库第三步用 Jaccard 相似度算图片之间关联第四步排序并过滤已看过的第五步按顺序返回对象。参数说明top_n 控制推荐数量默认 8相似度阈值没设因为数据量小的时候全排也没问题。这个方案在毕设数据量下完全够用而且不增加部署负担。5.2 数据验证用 Django shell 快速检查推荐结果写完推荐函数别急着改模板先在 shell 里验证。python manage.py shell# 在 shell 里测试推荐 from django.contrib.auth.models import User from app.views import recommend_for_user user User.objects.get(usernametestuser) recs recommend_for_user(user, top_n5) for img in recs: print(img.id, img.title, img.is_recommend)逻辑说明先拿一个测试用户调用推荐函数打印结果。如果返回空列表检查该用户有没有评论记录如果报错看倒排表构建时字段名对不对。我一般会造几条测试评论数据确保不同用户对同一批图片有交叉评论这样相似度才有值。5.3 模板里怎么接推荐结果视图里把推荐列表传给模板模板里循环渲染。# views.py 首页视图 def index(request): if request.user.is_authenticated: recommendations recommend_for_user(request.user) else: recommendations ImageInfo.objects.filter(is_recommendTrue)[:8] return render(request, index.html, {recommendations: recommendations})!-- index.html 推荐区 -- div classrecommend-list {% for img in recommendations %} div classcard img src{{ img.image.url }} alt{{ img.title }} h3{{ img.title }}/h3 p{{ img.dimensions }} | {{ img.format }}/p /div {% empty %} p暂无推荐先去评论几张图吧。/p {% endfor %} /div逻辑说明登录用户走个性化推荐未登录走热门推荐模板里用 {% empty %} 处理空结果避免页面空白。参数说明img.image.url 是 ImageField 自动生成的访问路径前提是 MEDIA_URL 配对了。5.4 一个我踩过的坑评论数据太少导致推荐为空刚开始测试的时候我造了 10 张图但只有 1 个用户评论过倒排表里每张图的用户集合几乎不重叠相似度全是 0推荐结果直接空。后来我写了个批量造评论的脚本模拟 5 个用户对 20 张图随机评论推荐才跑出效果。所以如果你拿到资源后发现推荐区一直空先看评论表里有没有足够多的交叉数据。从那以后我每次调推荐逻辑都强制先跑一遍数据填充脚本不然就是对着空列表干瞪眼。希望帮到你。本文还有配套的精品资源点击获取