
去年冬天一个做独立音乐人的朋友找到我说想有个地方展示自己的作品。我翻了三天 GitHub愣是没找到一个既好用又能二次开发的开源音乐项目。既然没有合适的那就自己写一个吧。这就是 Py-Music 的起点。 一、项目定位与技术选型1.1 它能做什么Py-Music 不是“又一个仿 QQ 音乐”而是一个功能完整的音乐社区底座。它面向三类人群独立音乐人用这个平台做作品集展示歌曲、专辑、个人简介全栈学习者通过这个项目理解 Django Vue 3 的实战整合毕设选手拿来即用也能按需扩展核心功能覆盖了音乐平台的常见需求歌曲上传与播放、歌手专辑管理、歌单收藏、社区动态、评论互动、关注关系……基本上一个音乐社区该有的它都具备了。1.2 技术选型为什么是 Django Vue 3后端Django 5.x DRF选择 Django核心原因是它的Admin 后台。对于需要频繁管理歌曲、歌手、轮播图的内容型项目Django Admin django-simpleui 可以秒出一个漂亮的管理界面省去大量后台开发时间。配合 DRF 的 ViewSet ModelSerializerCRUD 接口几乎是一行代码的事。前端Vue 3 TypeScript Pinia Tailwind CSSVue 的模板语法接近原生 HTML对新手友好Composition API 在大型项目中也不输阵。Pinia 比 Vuex 轻量很多配合 TypeScript 的类型推导状态管理的代码量直接砍半。Tailwind CSS 的原子化类让样式开发几乎不用离开 HTML 模板开发效率非常直观。认证方案JWTdjangorestframework-simplejwt前后端分离架构下JWT 是无状态认证的天然选择。配合 refresh token 机制在安全和体验之间取得了平衡。️ 二、后端模块设计2.1 模块划分按业务领域拆分为 6 个独立应用实现高内聚低耦合模块职责users注册登录、个人信息、关注关系music歌曲 CRUD、点赞、热门/新歌推荐artist歌手管理、专辑管理、歌曲数量自动统计playlist歌单 CRUD、歌曲添加/移除、公开/私有community动态发布、评论回复、点赞收藏system轮播图、导航菜单、文件上传每个模块遵循标准结构models.py→serializers.py→views.py→urls.py确保代码组织清晰新人也能快速定位。2.2 核心数据模型设计用户模块关注关系的双向查询classFollow(models.Model):followermodels.ForeignKey(User,on_deletemodels.CASCADE,related_namefollowing_set)followingmodels.ForeignKey(User,on_deletemodels.CASCADE,related_namefollowers_set)created_atmodels.DateTimeField(auto_now_addTrue)通过related_name明确区分「我关注的人」和「关注我的人」避免 ORM 查询时的语义混淆。音乐模块冗余字段提升性能⚡classSong(models.Model):titlemodels.CharField(max_length255)srcmodels.FileField(upload_toaudio/%Y/%m)covermodels.ImageField(upload_toimage/%Y/%m,nullTrue,blankTrue)play_countmodels.IntegerField(default0)# 冗余字段like_countmodels.IntegerField(default0)# 冗余字段singermodels.ForeignKey(artist.Singer,on_deletemodels.SET_NULL,nullTrue)lyricmodels.TextField(blankTrue,default)# LRC 格式歌词播放量、点赞数冗余存储避免每次列表查询都做关联聚合接口响应时间从~200ms 降到 ~50ms。歌单模块多对多关系classPlaylist(models.Model):usermodels.ForeignKey(User,on_deletemodels.CASCADE,related_nameplaylists)songsmodels.ManyToManyField(music.Song,related_nameplaylists,blankTrue)is_publicmodels.BooleanField(defaultTrue)歌单与歌曲是多对多关系前端传入歌曲 ID 列表即可批量关联序列化器负责处理新增和删除的 diff。效果预览歌单管理界面创建 / 编辑 / 收藏2.3 信号机制自动维护冗余数据 在artist/signals.py中利用 Django 信号自动更新专辑的歌曲数量receiver(post_save,senderSong)receiver(post_delete,senderSong)defupdate_album_song_count(sender,instance,**kwargs):ifinstance.album:instance.album.song_countinstance.album.songs.count()instance.album.save(update_fields[song_count])相比定时任务或手动维护信号机制实时性好、代码耦合度低。创建、删除、更新歌曲时自动触发无需在多个视图里重复维护逻辑。2.4 序列化器的分层设计 列表接口和详情接口使用不同的序列化器列表接口只返回 ID 和关键字段避免 N1 查询详情接口通过SerializerMethodField嵌套返回歌手、专辑的完整信息classSongDetailSerializer(serializers.ModelSerializer):singerserializers.SerializerMethodField()albumserializers.SerializerMethodField()defget_singer(self,obj):returnSingerSimpleSerializer(obj.singer).dataifobj.singerelseNone创建和更新也拆分为独立的序列化器避免在同一个类里堆砌复杂的required条件逻辑代码可读性更好。2.5 统一响应格式与全局异常处理 ️所有 API 接口返回统一结构{code:200,message:操作成功,data:{...}}全局异常处理器统一捕获 ValidationError、PermissionDenied、IntegrityError 等返回格式化的错误响应前端只需一套逻辑即可处理所有接口。 三、前端架构与状态管理3.1 目录结构 src/ ├── api/ # 按业务拆分的接口层song.ts, user.ts, playlist.ts... ├── components/ # 可复用组件Player, Navbar, SongList... ├── stores/ # Pinia 状态管理auth, player, playlist, navigation... ├── views/ # 页面视图Home, Discover, Singer, Play... ├── router/ # 路由配置 路由守卫 ├── types/ # TypeScript 类型定义 └── utils/ # 工具函数时间格式化、歌词解析...3.2 Pinia Store 拆分 ️Store职责auth用户登录状态、Token 管理、用户信息player播放列表、当前歌曲、播放状态、进度、音量playlist歌单列表、当前歌单详情navigation动态菜单数据从 API 加载ui全局 Loading、弹窗状态播放器 Store 的核心逻辑exportconstusePlayerStoredefineStore(player,(){constcurrentSongrefSong|null(null)constplaylistrefSong[]([])constisPlayingref(false)constprogressref(0)constvolumeref(0.8)constplay(song:Song){/* ... */}consttoggle(){isPlaying.value!isPlaying.value}constnext(){/* 从 playlist 取下一首 */}constprev(){/* 从 playlist 取上一首 */}return{currentSong,playlist,isPlaying,progress,volume,play,toggle,next,prev}})3.3 全局播放器组件 播放器悬浮在页面底部所有视图共享同一个播放实例。关键实现细节歌词同步后端返回 LRC 格式歌词前端解析为[{time, text}]数组通过requestAnimationFrame驱动高亮更新。setInterval精度不足换用rAF后歌词与音频的同步误差控制在±50ms以内。无缝切换提前加载下一首音频在当前歌曲播放到80%时开始缓冲切换时几乎无感知 ✨。状态持久化播放列表和进度写入localStorage刷新页面后恢复。效果预览底部全局播放器含歌词展示3.4 动态路由与菜单 导航菜单从后端 API 动态加载通过路由守卫在页面加载前注入路由// router/guard.tsrouter.beforeEach(async(to,from,next){constnavStoreuseNavigationStore()if(!navStore.isLoaded){awaitnavStore.fetchNavigations()navStore.injectRoutes()// 动态添加路由}next()})API 失败时降级到本地静态菜单数据确保页面始终可访问。 四、核心功能实现要点4.1 热门推荐与轮播图 ️首页展示轮播图、热门歌曲、新歌首发、热门歌单四个模块。所有数据从后端 API 获取前端通过onMounted并发请求Promise.allSettled处理部分接口失败的情况保证页面整体可用。效果预览首页轮播 热门推荐4.2 社区动态时间线采用「拉模式」实现动态时间线用户登录后后端返回其关注的人的最新动态按时间倒序排列支持分页前端配合IntersectionObserver实现无限滚动// 无限滚动核心逻辑constobservernewIntersectionObserver((entries){if(entries[0].isIntersecting!loading.valuehasMore.value){loadMore()}})帖子支持图片、文字、视频多种类型评论支持嵌套回复点赞和收藏独立计数 。效果预览社区动态瀑布流 评论框4.3 歌手与专辑筛选 歌手列表支持按字母、地区、性别、风格四维筛选前端通过 URL query 参数传递筛选条件后端使用 DRF 的FilterSet处理组合查询。专辑详情页自动统计歌曲数量通过信号机制实时更新无需额外查询。效果预览歌手详情页热门歌曲 专辑列表 五、踩坑与优化5.1 JWT 刷新令牌生命周期 ⏰问题未配置 refresh token 的有效期用户第二天打开页面需要重新登录。解决在settings.py中配置REFRESH_TOKEN_LIFETIME timedelta(days7)前端在 access token 过期时自动调用/api/refresh接口续期用户无感知。5.2 CORS 预检请求拦截 问题django-cors-headers配置了白名单但OPTIONS预检请求仍被拦截。解决补充配置CORS_ALLOW_METHODS[DELETE,GET,OPTIONS,PATCH,POST,PUT]5.3 播放器状态管理混乱 问题一开始把播放状态、用户信息、歌单全部塞在一个 store 里代码臃肿且难以调试。解决拆分为auth、player、playlist、navigation、ui五个独立 store职责边界清晰维护成本大幅降低。5.4 歌词同步精度问题 问题setInterval在浏览器标签页切到后台时会被节流导致歌词高亮滞后。解决换用requestAnimationFrame以音频的currentTime为基准驱动歌词渲染不再依赖定时器精度。 六、项目运行与部署6.1 后端启动 # 克隆项目gitclonerepository-urlcdpy-music# 创建虚拟环境python-mvenv venvsourcevenv/bin/activate# Windows: venv\Scripts\activate# 安装依赖pipinstall-rrequirements.txt# 数据库迁移python manage.py makemigrations python manage.py migrate# 创建超级管理员python manage.py createsuperuser# 启动服务python manage.py runserver0.0.0.0:8000访问地址管理后台http://localhost:8000/admin/API 接口http://localhost:8000/api/6.2 前端启动 ⚡cdweb-musicnpminstallnpmrun dev开发服务器默认运行在http://localhost:5173支持热更新。6.3 环境变量配置 ⚙️后端关键配置项位于py_music/settings.py# JWT 有效期SIMPLE_JWT{ACCESS_TOKEN_LIFETIME:timedelta(hours2),REFRESH_TOKEN_LIFETIME:timedelta(days7),}# CORS生产环境应配置具体域名CORS_ALLOW_ALL_ORIGINSTrue# 媒体文件存储MEDIA_URL/media/MEDIA_ROOTos.path.join(BASE_DIR,media) 七、未来可扩展方向项目当前已具备完整功能后续可以继续探索的方向个性化推荐基于协同过滤算法根据用户收听历史推荐相似歌曲实时互动用 WebSocket 实现直播间或「一起听」功能付费内容支持独立音乐人发布付费单曲或专辑排行榜按播放量、点赞数、收藏数生成周榜/月榜 八、写在最后这个项目从需求到落地前后花了几个月时间。它不是那种“一键生成”的脚手架而是一个从业务出发、经过多次重构的完整系统。如果你正在学习全栈开发或者需要一个音乐类项目的起点它应该能帮到你。项目地址 https://gitee.com/walii/py-music欢迎查阅源码、提出改进建议。如果这个项目对你有帮助不妨给它点个 Star ⭐让更多人能看到它。音乐无界代码有爱。希望 Py-Music 能成为你技术探索路上的一个小小驿站。✨