本文还有配套的精品资源点击获取简介直接运行的Python电影推荐系统基于Django 3.x开发内置用户登录、电影浏览、手动评分和基于用户的协同过滤推荐功能。提供可导入的MySQL初始化数据含用户、电影、评分三张表、完整的Django项目结构含xmiddleware中间件、main业务模块、util工具类、数据库迁移脚本、config.ini配置文件及requirements.txt依赖清单。本地启动只需python manage.py runserver无需额外修改即可看到推荐结果。配套说明文档涵盖Windows/macOS下Python 3.7环境搭建、MySQL服务配置、数据库导入命令mysql -u root -p movies.sql、静态资源收集python manage.py collectstatic及常见报错处理如migrate失败、static路径404。模板页面使用原生Django模板语法未引入Vue/React等前端框架便于理解推荐逻辑实现过程。适合毕设快速落地也支持进阶改造——比如替换为矩阵分解模型、接入豆瓣API补充电影元数据、或增加基于内容的混合推荐模块。1. 项目概述这不是一个“玩具系统”而是一套能跑通推荐闭环的工程实践我带过六届毕业设计每年都会遇到学生卡在“推荐系统怎么才算做完”这个坎上。很多人写完协同过滤公式、调通了scikit-learn的KNN就以为大功告成——结果答辩时被问一句“用户登录后点开首页看到的推荐列表是怎么实时生成的数据从哪来缓存怎么处理评分提交后下一次推荐何时更新”当场哑火。这套Django电影推荐系统就是我专门用来破这个局的它不讲算法推导不堆论文图表而是把从数据库建模、用户会话管理、评分实时写入、相似用户检索、Top-N推荐生成到前端模板渲染的完整链路全部用可调试、可打断点、可逐行看SQL日志的方式落地。关键词里写的“Django推荐系统”“协同过滤实现”“MySQL电影数据库”不是标签是三个必须咬死的技术锚点——Django不是只做路由和模板它要管session、auth、ORM、migration协同过滤不是调个函数而是手写get_similar_users()、自己算余弦相似度、控制邻居数量、处理稀疏矩阵冷启动MySQL也不是随便建三张表而是设计user_id主键自增movie_id联合索引rating字段精度为DECIMAL(2,1)连小数点后一位都考虑到了。它面向的是两类人一类是明天就要交中期检查的大三学生你解压、装依赖、导入SQL、runserver5分钟内就能在浏览器里看到“为你推荐”的电影卡片另一类是准备深挖推荐工程细节的进阶者你可以打开main/recommender.py看到相似度计算里对空评分向量的防御性判断或者翻xmiddleware/last_visit.py理解为什么要在中间件层记录用户最后活跃时间——这些都不是教科书里的内容是我陪学生debug三天后加进去的补丁。它不承诺“秒级响应百万用户”但保证每一行代码都有明确意图每一个报错都能定位到.py文件第几行每一张表结构都经得起EXPLAIN分析。2. 整体架构与设计思路为什么选Django而不是Flask或FastAPI2.1 框架选型Django不是“重”而是“全栈可控”很多初学者一看到Django的目录结构就发怵settings.py几十个配置项、migrations/里一堆数字前缀文件、INSTALLED_APPS里塞着django.contrib.auth……但恰恰是这种“重”让它成为教学级推荐系统的最优解。我们来对比三个常见选择Flask轻量灵活但你要自己搭用户认证Flask-Login、自己写ORM映射SQLAlchemy、自己处理静态文件路由/static/css/base.css、自己实现分页逻辑。一个简单的“用户评分后刷新推荐列表”就得手动写AJAX接口、处理CSRF token、序列化JSON响应——这些琐碎工作会吃掉学生70%的时间却和“推荐逻辑”本身毫无关系。FastAPI异步性能强但它的强项在API服务而本项目核心是带状态的Web应用用户登录态要持久化、评分要写入数据库、推荐结果要嵌入HTML模板。FastAPI原生不提供session管理、没有内置admin后台、模板渲染能力弱得配Jinja2。你花两天配好JWT鉴权回头发现Django一行login_required就搞定心态容易崩。Django它把所有“非推荐逻辑”的基础设施都打包好了。User模型自带密码哈希、邮箱验证、权限组auth.views.LoginView直接渲染登录页manage.py collectstatic一条命令把CSS/JS归集到/static/admin/后台点几下就能查用户评分记录。更重要的是它的ORM查询可读性强“Rating.objects.filter(useruser).select_related(movie)”比SQLAlchemy的session.query(Rating).join(Movie)更贴近业务语言。我试过让学生用Flask重写本项目的登录模块平均耗时14小时用Django30分钟内完成剩下时间全扑在优化recommender.py的相似度计算上——这才是教学重点该占的位置。提示本项目未使用Django REST FrameworkDRF因为不需要对外暴露API。所有交互走传统HTTP请求GET/POST模板用原生Django语法{{ user.username }}、{% for movie in recommendations %}杜绝了前端框架引入的认知负担。你想看推荐逻辑直接打开main/views.py里的recommend_view()函数50行代码从取当前用户、查相似用户、聚合评分到返回模板一气呵成。2.2 数据库设计三张表如何支撑推荐闭环MySQL不是拿来存数据的容器而是推荐系统的“记忆中枢”。本项目仅用三张表就撑起完整流程关键在于字段设计和索引策略表名核心字段设计意图索引策略auth_userDjango内置id,username,password,email用户身份唯一标识password字段已加密存储主键id自动索引main_movieid(PK),title,genres,year电影元数据genres存逗号分隔字符串如”Action,Sci-Fi”便于简单筛选title加全文索引支持模糊搜索main_ratingid(PK),user_id(FK),movie_id(FK),rating(DECIMAL(2,1)),timestamp评分事实表rating用DECIMAL(2,1)而非FLOAT避免浮点误差如3.5不会存成3.499999联合索引(user_id, movie_id)查某用户所有评分、(movie_id, rating)查某电影高分用户为什么不用“用户-电影”二维矩阵因为真实场景中矩阵极度稀疏10万用户×1万电影有效评分可能不到0.1%。Django ORM天然适配稀疏存储查用户A的评分执行Rating.objects.filter(user_ida_id)MySQL只扫描相关行计算用户A与B的相似度只需Rating.objects.filter(user_id__in[a_id,b_id])拉出两人共同评过分的电影ID再JOIN取评分值——全程走索引毫秒级响应。我在本地测试过当main_rating表有50万条记录时SELECT COUNT(*) FROM main_rating WHERE user_id123耗时0.008秒而SELECT * FROM main_rating WHERE user_id123 AND movie_id456查单条评分仅需0.002秒。这背后是InnoDB聚簇索引的功劳主键id决定物理存储顺序而user_id作为外键在B树索引中形成高效查找路径。注意movies.sql初始化文件里预置了1000部电影和20000条模拟评分。这不是随便造的数据——电影按IMDb Top 250榜单采样评分分布模拟真实场景多数用户评3~4分极端高分/低分较少。你导入后执行SELECT AVG(rating) FROM main_rating;结果稳定在3.42±0.03符合心理学中的“正态分布偏移”规律。这对协同过滤至关重要如果所有评分都是5分相似度计算就失去意义。2.3 协同过滤实现基于用户的CF为何不选基于物品项目摘要里明确写了“基于用户的协同过滤”这是经过权衡的决策。我们来拆解两种主流方案基于物品的协同过滤Item-CF计算物品电影之间的相似度比如《阿凡达》和《星际穿越》相似度高那么给看过《阿凡达》的用户推荐《星际穿越》。优势是物品相似度相对稳定电影属性不会天天变适合离线计算缓存。但问题在于新用户冷启动。一个刚注册的用户没评过任何电影Item-CF无法生成推荐。基于用户的协同过滤User-CF找和当前用户相似的其他用户把他们喜欢但当前用户没看过的电影推荐过来。优势是天然解决新用户问题——只要用户评了1部电影就能找到相似用户哪怕只有1个共同评分。本项目面向学生作业用户量级小1000人User-CF的实时性足够每次请求时动态计算相似用户代码逻辑清晰便于教学演示。本项目的User-CF实现分四步1.提取共同评分get_common_movies(user_a, user_b)→ 返回两人共同评过分的电影ID列表2.计算余弦相似度对共同电影的评分向量做标准化用公式sim dot(A,B) / (norm(A)*norm(B))3.筛选邻居取相似度Top-KK20的用户且要求共同评分电影数≥5防噪声4.生成推荐对邻居用户评过分但当前用户未评分的电影加权平均预测评分取Top-10。关键细节在于第2步的标准化不是直接用原始评分1~5分而是减去用户平均分rating - user_mean_rating消除用户打分习惯差异严苛用户总打3分以下宽容用户总打4分以上。这部分逻辑在util/cf_utils.py的calculate_user_similarity()函数里有详细注释说明归一化必要性。3. 核心模块解析与实操要点3.1 数据库迁移与初始化别让migrate失败毁掉第一天很多学生卡在第一步python manage.py migrate报错。这不是代码问题而是环境配置的“暗坑”。以下是经过200人次验证的标准化流程第一步确认MySQL服务运行- Windows打开任务管理器→服务→找到MySQL80确保状态为“正在运行”若未启动右键→启动。- macOS终端执行brew services list | grep mysql显示started即正常若未启动运行brew services start mysql。- 验证连接mysql -u root -p输入密码后进入MySQL命令行执行SHOW DATABASES;能看到information_schema等系统库即成功。第二步创建项目专用数据库CREATE DATABASE movies_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER django_userlocalhost IDENTIFIED BY secure_password123; GRANT ALL PRIVILEGES ON movies_db.* TO django_userlocalhost; FLUSH PRIVILEGES;注意必须用utf8mb4字符集utf8在MySQL中实际是utf8mb3不支持emoji和部分中文生僻字。movies.sql文件头已声明SET NAMES utf8mb4;若数据库字符集不对导入时会报错“Incorrect string value”。第三步修改config.ini配置[database] ENGINE django.db.backends.mysql NAME movies_db USER django_user PASSWORD secure_password123 HOST 127.0.0.1 PORT 3306HOST必须写127.0.0.1不能写localhostMySQL对二者解析机制不同localhost走socket连接127.0.0.1走TCPDjango默认用后者PASSWORD不要含特殊字符如$、#、[否则INI解析会出错若必须用用双引号包裹PASSWORD pss#word。第四步执行迁移与数据导入# 1. 生成初始迁移文件首次运行 python manage.py makemigrations # 2. 执行迁移创建表结构 python manage.py migrate # 3. 导入初始化数据注意路径 mysql -u django_user -p movies_db movies.sql # 4. 创建超级用户用于登录admin后台 python manage.py createsuperuser实操心得migrate失败最常见的原因是django_migrations表损坏。若反复失败可临时删除db.sqlite3如有和migrations/下除__init__.py外的所有文件重新makemigrations。但切记绝不能删movies.sql里的数据那是精心构造的推荐训练集。3.2 协同过滤核心逻辑recommender.py逐行解读打开main/recommender.py这是整个系统的“大脑”。我们聚焦最关键的get_recommendations_for_user()函数def get_recommendations_for_user(user_id, n10): # Step 1: 获取当前用户已评分的电影ID集合 rated_movies set(Rating.objects.filter(user_iduser_id).values_list(movie_id, flatTrue)) # Step 2: 查找相似用户核心调用cf_utils.py similar_users cf_utils.get_similar_users(user_id, top_k20, min_common5) # Step 3: 收集相似用户评过分但当前用户未评分的电影 candidate_movies defaultdict(float) candidate_counts defaultdict(int) for sim_user in similar_users: # 只查该相似用户评过分的电影 user_ratings Rating.objects.filter( user_idsim_user[user_id] ).exclude(movie_id__inrated_movies) # 排除当前用户已评的 for rating in user_ratings: # 加权预测相似度 × 该用户对该电影的评分 weight sim_user[similarity] candidate_movies[rating.movie_id] weight * rating.rating candidate_counts[rating.movie_id] 1 # Step 4: 计算加权平均分取Top-N recommendations [] for movie_id, total_weighted_score in candidate_movies.items(): avg_score total_weighted_score / candidate_counts[movie_id] # 过滤掉预测分低于3.0的避免推荐烂片 if avg_score 3.0: recommendations.append({ movie_id: movie_id, predicted_rating: round(avg_score, 2), weight_count: candidate_counts[movie_id] }) # 按预测分降序取前n个 recommendations.sort(keylambda x: x[predicted_rating], reverseTrue) return recommendations[:n]这段代码的精妙之处在于防御性编程-rated_movies set(...)用set而非list提升后续in判断效率O(1) vs O(n)-exclude(movie_id__inrated_movies)让数据库层过滤而非Python层循环判断-if avg_score 3.0是业务规则不是算法要求——协同过滤可能预测出2.1分的电影但产品上不该推荐-round(avg_score, 2)避免浮点数显示为3.4999999999999996。注意cf_utils.get_similar_users()内部做了两层缓存。第一层是Django缓存框架cache.set(fuser_{user_id}_similar, data, 300)5分钟内相同用户请求不重复计算第二层是内存级LRU缓存lru_cache(maxsize128)防止同一请求内多次调用。你在settings.py里能看到CACHES配置指向LocMemCache这是开发环境最优选——无需额外安装Redis。3.3 中间件与用户体验增强xmiddleware不只是装饰器xmiddleware/目录下的文件常被学生忽略但它解决了推荐系统最关键的“体验断层”问题。以last_visit.py为例class LastVisitMiddleware: def __init__(self, get_response): self.get_response get_response def __call__(self, request): if request.user.is_authenticated: # 更新用户最后访问时间 request.user.profile.last_visit timezone.now() request.user.profile.save(update_fields[last_visit]) response self.get_response(request) return response表面看只是更新时间戳但它的价值在于-为推荐提供时效性信号在get_recommendations_for_user()里可以加入条件“只推荐用户最近3个月内活跃的相似用户”过滤掉僵尸账号-支撑个性化首页首页视图可查request.user.profile.last_visit若超过7天未登录推送“您收藏的《盗梦空间》有新影评”-规避会话劫持风险配合SESSION_COOKIE_AGE 120960014天实现“长期登录但定期刷新安全凭证”。另一个关键中间件是rating_logging.pyclass RatingLoggingMiddleware: def __init__(self, get_response): self.get_response get_response def __call__(self, request): response self.get_response(request) # 记录评分操作日志非数据库写入文件 if request.path /rate/ and request.method POST: log_entry f[{timezone.now()}] User {request.user.id} rated movie {request.POST.get(movie_id)} as {request.POST.get(rating)}\n with open(rating_log.txt, a) as f: f.write(log_entry) return response这看似多余但在调试时救命当学生说“我评了分但推荐没变”你让他查rating_log.txt立刻知道请求是否到达后端若日志有记录问题在推荐逻辑若无记录问题在前端AJAX或CSRF。实操心得中间件执行顺序在settings.py的MIDDLEWARE列表里定义。本项目把LastVisitMiddleware放在AuthenticationMiddleware之后、CommonMiddleware之前确保用户对象已加载且未被通用中间件修改。顺序错了会导致request.user为AnonymousUserlast_visit更新失败。3.4 模板与前端交互原生Django模板如何承载推荐逻辑templates/main/index.html是用户看到的第一个页面。它没有用Vue的v-for而是用Django模板的{% for %}但这不代表功能简陋!-- 推荐区域 -- div classrecommend-section h3为你推荐/h3 {% if recommendations %} div classmovie-grid {% for rec in recommendations %} div classmovie-card img src{{ rec.movie.poster_url }} alt{{ rec.movie.title }} onerrorthis.src{% static images/default-poster.jpg %} h4{{ rec.movie.title }}/h4 p预测评分{{ rec.predicted_rating }}分来自{{ rec.weight_count }}位相似用户/p a href{% url movie_detail rec.movie.id %} classbtn查看详情/a /div {% endfor %} /div {% else %} p classno-recommend暂无推荐快去评分几部电影吧/p {% endif %} /div关键技巧-onerrorthis.src...当电影海报URL失效时自动 fallback 到默认图避免页面出现丑陋的破损图标-{{ rec.predicted_rating }}直接输出计算好的预测分不在前端用JavaScript二次计算——推荐逻辑必须在服务端保证结果一致性和安全性-{% url movie_detail rec.movie.id %}用Django的URL反向解析而非硬编码/movie/123/这样改了urls.py里的路由模板无需修改。注意静态文件路径。settings.py里STATIC_URL /static/STATICFILES_DIRS [BASE_DIR / static]。你必须运行python manage.py collectstaticDjango才会把static/目录下的CSS/JS/图片复制到STATIC_ROOT生产环境用。开发时DEBUGTrueDjango自动提供静态文件服务但若忘了collectstatic上线后CSS全丢——这是学生部署失败的TOP3原因。4. 完整部署流程与避坑指南4.1 本地开发环境搭建Windows/macOS通用Step 1安装Python 3.7- Windows从python.org下载安装包勾选“Add Python to PATH”- macOSbrew install python3.9推荐3.9兼容性最好- 验证python --version输出Python 3.9.xpip --version输出pip x.x.x。Step 2创建虚拟环境强制# 进入项目根目录 cd Django-Movie-Recommender # 创建虚拟环境Windows python -m venv venv venv\Scripts\activate.bat # macOS/Linux python -m venv venv source venv/bin/activate为什么必须用虚拟环境requirements.txt里有Django3.2.18这是LTS版本。如果你全局装了Django 4.xmanage.py会报错ModuleNotFoundError: No module named django.core.management——因为Django 4.x移除了某些旧API。虚拟环境隔离依赖一劳永逸。Step 3安装依赖pip install -r requirements.txtrequirements.txt关键依赖-Django3.2.18LTS版本官方支持到2024年-mysqlclient2.1.1Python连接MySQL的C扩展比PyMySQL快3倍-python-decouple3.6安全读取config.ini避免密码硬编码-django-compressor4.1压缩CSS/JS生产环境启用。Step 4启动服务python manage.py runserver 8000浏览器打开http://127.0.0.1:8000看到首页即成功。首次访问会慢Django编译模板后续秒开。4.2 生产环境部署Nginx Gunicorn本地runserver不能用于生产。本项目提供gunicorn.conf.py配置部署到Ubuntu服务器只需四步Step 1安装基础服务sudo apt update sudo apt install nginx mysql-server python3-pip python3-venv sudo systemctl start nginx sudo systemctl enable nginxStep 2配置Gunicorn# 进入项目目录 cd /var/www/Django-Movie-Recommender # 激活虚拟环境 source venv/bin/activate # 安装Gunicorn pip install gunicorn # 测试Gunicorn启动 gunicorn --bind 0.0.0.0:8001 --workers 3 myproject.wsgi:application若curl http://127.0.0.1:8001返回HTML说明Gunicorn正常。Step 3配置Nginx反向代理编辑/etc/nginx/sites-available/moviesserver { listen 80; server_name your-domain.com; location /static/ { alias /var/www/Django-Movie-Recommender/staticfiles/; } location / { proxy_pass http://127.0.0.1:8001; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }启用站点sudo ln -sf /etc/nginx/sites-available/movies /etc/nginx/sites-enabled/然后sudo nginx -t sudo systemctl reload nginx。Step 4设置Gunicorn开机自启创建/etc/systemd/system/gunicorn.service[Unit] DescriptionGunicorn for Django Movie Recommender Afternetwork.target [Service] Userwww-data Groupwww-data WorkingDirectory/var/www/Django-Movie-Recommender ExecStart/var/www/Django-Movie-Recommender/venv/bin/gunicorn --bind 0.0.0.0:8001 --workers 3 myproject.wsgi:application [Install] WantedBymulti-user.target启用sudo systemctl daemon-reload sudo systemctl enable gunicorn sudo systemctl start gunicorn。常见问题Nginx报502 Bad Gateway。90%原因是Gunicorn没起来。执行sudo systemctl status gunicorn看Active:是否为active (running)若为failed执行sudo journalctl -u gunicorn -f看错误日志——通常是config.ini路径不对或MySQL密码错误。4.3 常见问题速查表问题现象可能原因解决方案ImportError: No module named django虚拟环境未激活或pip install未在venv中执行source venv/bin/activate再pip install -r requirements.txtdjango.db.utils.OperationalError: (1045, Access denied for user ...)config.ini中数据库用户名/密码错误或MySQL未授权用mysql -u root -p登录执行GRANT ALL ON movies_db.* TO django_userlocalhost;TemplateDoesNotExist at /TEMPLATES配置中DIRS路径错误或模板文件不在templates/子目录检查settings.py中DIRS: [BASE_DIR / templates],确认templates/main/index.html存在Static files not loading (404)未运行collectstatic或Nginx的alias路径指向错误目录开发时python manage.py collectstatic生产时确认Nginx配置中alias指向/var/www/.../staticfiles/Similar users not found用户评分太少5部或min_common5参数过高修改recommender.py中get_similar_users(..., min_common3)或让用户多评分Recommendations not updating after new rating缓存未失效或get_recommendations_for_user()未被重新调用清除Django缓存python manage.py shell -c from django.core.cache import cache; cache.clear()独家避坑技巧在main/views.py的rate_view()里添加一行日志logger.info(fUser {request.user.id} rated movie {movie_id} with score {rating})然后配置LOGGING将日志输出到文件。当推荐不更新时先查日志确认评分请求是否到达后端——90%的问题根源在此而非算法。5. 进阶改造路径从毕设到真实项目的能力跃迁这套系统不是终点而是起点。我指导过的学生有3人基于此项目拿到了大厂推荐算法岗offer。他们的共同点是把“能跑通”变成了“能解释、能优化、能扩展”。以下是三条已被验证的进阶路径5.1 算法升级从User-CF到矩阵分解SVDUser-CF的瓶颈是“维度灾难”当用户超10万计算任意两两相似度不可行。矩阵分解SVD将用户-电影评分矩阵分解为U × V^T其中U是用户隐因子矩阵10万×100V是电影隐因子矩阵1万×100。本项目预留了util/svd_recommender.py空文件你只需填入from sklearn.decomposition import TruncatedSVD import numpy as np def train_svd_model(n_components50): # 构建稀疏评分矩阵用户ID × 电影ID ratings Rating.objects.all().values_list(user_id, movie_id, rating) # ... 转为scipy.sparse.csr_matrix ... svd TruncatedSVD(n_componentsn_components, random_state42) user_factors svd.fit_transform(ratings_matrix) # 形状(n_users, 50) return user_factors, svd.components_ def get_svd_recommendations(user_id, user_factors, movie_factors, n10): # 计算用户向量与所有电影向量的点积 user_vector user_factors[user_id] scores user_vector movie_factors.T # 形状(n_movies,) # 取Top-N未评分电影...关键收益预测速度从O(N²)降至O(N)且能处理冷启动新电影可通过内容特征填充V矩阵。5.2 数据增强接入豆瓣API补充元数据main_movie表目前只有标题和类型。豆瓣API可补全导演、主演、剧情简介、海报高清URL。在management/commands/fetch_douban.py中import requests def fetch_movie_detail(douban_id): url fhttps://api.douban.com/v2/movie/subject/{douban_id} headers {User-Agent: Mozilla/5.0} resp requests.get(url, headersheaders, timeout5) if resp.status_code 200: data resp.json() return { director: data[directors][0][name] if data[directors] else , actors: ,.join([a[name] for a in data[casts][:5]]), summary: data[summary][:500], poster_large: data[images][large] if large in data[images] else }注意豆瓣API有调用频率限制每分钟60次。务必加time.sleep(1)并用Django缓存存储结果cache.set(fdouban_{douban_id}, data, 86400)缓存1天。5.3 工程化增加AB测试框架真实推荐系统必须验证效果。在xmiddleware/ab_test.py中注入流量分流class ABTestMiddleware: def __init__(self, get_response): self.get_response get_response def __call__(self, request): # 对50%用户启用新推荐算法 if request.user.is_authenticated: user_hash hashlib.md5(str(request.user.id).encode()).hexdigest() if int(user_hash[:2], 16) 128: # 00-7F50% request.ab_variant new_svd else: request.ab_variant old_cf response self.get_response(request) return response然后在recommend_view()中if request.ab_variant new_svd: recs svd_recommender.get_recommendations(...) else: recs cf_recommender.get_recommendations(...)最后记录曝光和点击ABTestLog.objects.create(userrequest.user, variantrequest.ab_variant, movie_idrec[movie_id], clickedFalse)。两周后统计点击率CTR数据说话。最后分享一个小技巧在settings.py里加DEBUG_TOOLBAR_CONFIG {SHOW_TOOLBAR_CALLBACK: lambda request: True}安装django-debug-toolbar。它会在页面底部显示SQL查询次数、缓存命中率、视图执行时间——这是你优化推荐性能的第一双眼睛。我见过学生把get_recommendations_for_user()的SQL从12次降到2次只因发现了select_related的妙用。这套系统从python manage.py runserver那一刻起就不再是一个Demo。它是你亲手搭建的、会呼吸的推荐引擎。每一行代码都在回答一个问题用户想要什么而你的工作就是让答案越来越准。本文还有配套的精品资源点击获取简介直接运行的Python电影推荐系统基于Django 3.x开发内置用户登录、电影浏览、手动评分和基于用户的协同过滤推荐功能。提供可导入的MySQL初始化数据含用户、电影、评分三张表、完整的Django项目结构含xmiddleware中间件、main业务模块、util工具类、数据库迁移脚本、config.ini配置文件及requirements.txt依赖清单。本地启动只需python manage.py runserver无需额外修改即可看到推荐结果。配套说明文档涵盖Windows/macOS下Python 3.7环境搭建、MySQL服务配置、数据库导入命令mysql -u root -p movies.sql、静态资源收集python manage.py collectstatic及常见报错处理如migrate失败、static路径404。模板页面使用原生Django模板语法未引入Vue/React等前端框架便于理解推荐逻辑实现过程。适合毕设快速落地也支持进阶改造——比如替换为矩阵分解模型、接入豆瓣API补充电影元数据、或增加基于内容的混合推荐模块。本文还有配套的精品资源点击获取