使用Python Django框架制作一个音乐网站,
本篇主要是歌手详情页-基本信息、单曲列表功能开发实现内容。
目录
歌手基本信息
增加路由
需要设置参数歌手id。
python
path('singer/detail/<int:id>', views.singer_detail, name='singer_detail'),
显示视图
查询歌手表模型,通过id查询响应歌手信息。
python
def singer_detail(request, id):
""" 歌手详情-基本信息 """
info = Singler.objects.get(pk=id)
return render(request, 'singer/detail.html', {'info': info})
模板显示
设置样式和在模板基础上改为视图中传递的歌手信息。
python
{% extends 'common/base.html' %}
{% load static %}
{% block title %}我的音乐-歌手{% endblock title %}
{% block content %}
<link rel="stylesheet" href="{% static 'css/singer_detail.css' %}">
<!--导航条开始-->
<div class="header">
<img src="{% static 'images/logo.png' %}" class="logo" alt="">
<ul>
<li><a href="{% url 'player:index' %}">推荐</a></li>
<li><a href="javascript:void(0)">排行榜</a></li>
<li><a href="javascript:void(0)" class="selected">歌手</a></li>
<li><a href="{% url 'player:singer' %}">单曲</a></li>
<li><a href="javascript:void(0)">歌单</a></li>
</ul>
</div>
<!--导航条结束-->
<!--歌手预告开始-->
<div class="singer">
<div class="singer_bg"></div>
<div class="singer_info flex_c">
<div class="singer_cover">
<img src="/media/{{info.portrait}}" alt="">
</div>
<div class="info">
<p class="flex_c"><span class="name">{{info.name}}</span></p>
<div class="info_items">
<span>单曲:<span class="num">{{info.singe_num}}</span></span>
<span>专辑:<span class="num">{{info.album_num}}</span></span>
<span>粉丝:<span class="num">100W</span></span>
</div>
<div class="singer_items flex_c">
<p>
<span>生日:<span>{{info.birthday}}</span></span>
<span>身高:<span>{{info.height}}cm</span></span>
<span>体重:<span>{{info.weight}}kg</span></span>
<span>星座:<span>{{info.constellation}}...</span></span>
</p>
<span class="all"><a href="{% url 'player:singer_detail' info.id %}">全部</a> > </span>
</div>
<div class="btns">
<button class="play"><i class="glyphicon glyphicon-play"></i> 播放全部歌曲</button>
<button><i class="glyphicon glyphicon-heart"></i> 收藏</button>
</div>
</div>
</div>
</div>
<!--歌手预告结束-->
<!--歌手资料开始-->
<div class="main_con">
<div class="con_l">
<ul class="tabs flex_c">
<li>
<span class=""><a href="{% url 'player:singer_song' 1 %}">单曲</a></span>
<span class=""><a href="{% url 'player:singer_album' 1 %}">专辑</a></span>
<span class="active">简介</span>
</li>
</ul>
<div class="child_view">
<p class="tit">基本信息</p>
<div class="list_info">
<div class="info_list flex_c">
<div class="item_l">
<span>姓名:<span class="text">{{info.name}}</span></span>
</div>
<div class="item_r">
<span>英文名:<span class="text">-</span></span>
</div>
</div>
<div class="info_list flex_c">
<div class="item_l">
<span>性别:<span class="text">男</span></span>
</div>
<div class="item_r">
<span>国籍:<span class="text">中国香港</span></span>
</div>
</div>
<div class="info_list flex_c">
<div class="item_l">
<span>生日:<span class="text">{{info.birthday}}</span></span>
</div>
<div class="item_r">
<span>星座:<span class="text">{{info.constellation}}</span></span>
</div>
</div>
<div class="info_list flex_c">
<div class="item_l">
<span>身高:<span class="text">{{info.height}}cm</span></span>
</div>
<div class="item_r">
<span>体重:<span class="text">{{info.weight}}kg</span></span>
</div>
</div>
</div>
<p class="tit">个人简介</p>
<p class="info">{{info.desc|safe}}</p>
</div>
</div>
</div>
<!--歌手资料结束-->
{% endblock content %}
推荐歌手跳转详情
在推荐页中推荐歌手增加跳转到歌手详情-基本信息页面的链接设置。
html
<div class="item">
<div class="cover">
<img src="/media/{{sg.portrait}}" alt="">
</div>
<p class="name"><a href="{% url 'player:singer_detail' sg.id %}">
{{sg.name}}</a></p>
<p class="num">{{sg.singe_num}}首歌曲</p>
</div>
歌手增加基本信息
表模型增加字段
player/models.py中歌手表模型增加英文名、国籍、性别字段。
内容如下:
python
english_name = models.CharField(
'英文名',
max_length=50,
help_text='请输入歌手英文名',
default='-'
)
gender = models.IntegerField(
'性别',
help_text='请选择歌手性别',
choices=((0, '女'), (1, '男')),
default=1
)
country_name = models.CharField(
'国籍',
max_length=50,
help_text='请输入歌手国籍',
default='-'
)
数据表更新
同样还要创建表迁移文件,然后执行更新表结构。
bash
python manage.py makemigrations
python manage.py migrate
效果如下:
基本信息增加内容渲染
表字段增加以后,对原来的歌手信息进行补录,最后对新增的信息进行模板渲染。
内容如下:
python
<div class="child_view">
<p class="tit">基本信息</p>
<div class="list_info">
<div class="info_list flex_c">
<div class="item_l">
<span>姓名:<span class="text">{{info.name}}</span></span>
</div>
<div class="item_r">
<span>英文名:<span class="text">{{info.english_name}}</span></span>
</div>
</div>
<div class="info_list flex_c">
<div class="item_l">
<span>性别:<span class="text">
{% if info.gender %}
男
{% else %}
女
{% endif %}
</span></span>
</div>
<div class="item_r">
<span>国籍:<span class="text">{{info.country_name}}</span></span>
</div>
</div>
歌手单曲列表
路由设置
需要设置参数歌手id、分页page。
python
path('singer/song/<int:id>/<int:page>', views.singer_song, name='singer_song'),
跳转设置
在歌手详情中单曲切换设置跳转链接。
python
<span class=""><a href="{% url 'player:singer_song' info.id 1 %}">单曲</a></span>
视图方法
还是先获取全部列表,然后传给分页组件得到分页条数。
python
def singer_song(request, id, page):
""" 歌手详情-单曲列表 """
# 歌手基本信息
info = Singler.objects.get(pk=id)
# 单曲列表
song_list = Singe.objects.filter(singler_id=id).all()
# 实例化Paginator
paginator = Paginator(song_list, 20)
# 获取当前页码数据
res = paginator.page(page)
return render(request, 'singer/song_list.html', {'info': info, 'songList': res})
模板内容
模板公共头信息
抽离出与歌手基本信息中相同的头部信息,
在singler文件夹中创建common.html文件,
做一个歌手公共头部内容页面。
内容如下:
python
{% load static %}
<!--导航条开始-->
<div class="header">
<img src="{% static 'images/logo.png' %}" class="logo" alt="">
<ul>
<li><a href="{% url 'player:index' %}">推荐</a></li>
<li><a href="javascript:void(0)" class="selected">歌手</a></li>
<li><a href="javascript:void(0)">单曲</a></li>
<li><a href="javascript:void(0)">歌单</a></li>
</ul>
</div>
<!--导航条结束-->
<!--歌手预告开始-->
<div class="singer">
<div class="singer_bg"></div>
<div class="singer_info flex_c">
<div class="singer_cover">
<img src="/media/{{info.portrait}}" alt="">
</div>
<div class="info">
<p class="flex_c"><span class="name">{{info.name}}</span></p>
<div class="info_items">
<span>单曲:<span class="num">{{info.singe_num}}</span></span>
<span>专辑:<span class="num">{{info.album_num}}</span></span>
<span>粉丝:<span class="num">100W</span></span>
</div>
<div class="singer_items flex_c">
<p>
<span>生日:<span>{{info.birthday}}</span></span>
<span>身高:<span>{{info.height}}cm</span></span>
<span>体重:<span>{{info.weight}}kg</span></span>
<span>星座:<span>{{info.constellation}}...</span></span>
</p>
<span class="all"><a href="{% url 'player:singer_detail' info.id %}">全部</a> > </span>
</div>
<div class="btns">
<button class="play"><i class="glyphicon glyphicon-play"></i> 播放全部歌曲</button>
<button><i class="glyphicon glyphicon-heart"></i> 收藏</button>
</div>
</div>
</div>
</div>
<!--歌手预告结束-->
单曲列表页面内容
单曲列表页面把原来的模板内容公共部分去掉,通过include引入进来。
接着就是for循环把单曲列表渲染出来;然后做一个分页列表,最后判断无数据显示
固定页面。
注意:需要把歌手基本信息页面也改为引入公共信息处理。
内容如下:
python
{% extends 'common/base.html' %}
{% load static %}
{% block title %}我的音乐-歌手{% endblock title %}
{% block content %}
<link rel="stylesheet" href="{% static 'css/singer_song.css' %}">
<!--歌手头部公共信息-->
{% include 'singer/common.html' %}
<!--歌手资料开始-->
<div class="main_con">
<div class="con_l">
<ul class="tabs flex_c">
<li>
<span class="active">单曲</span>
<span class=""><a href="javascript:void(0)">专辑</a></span>
<span class=""><a href="{% url 'player:singer_detail' 1 %}">简介</a></span>
</li>
</ul>
<div class="child_view">
<div class="list_head head_name_singer">
<ul class="flex_c">
<li class="head_num">序号</li>
<li class="head_name">歌曲</li>
<li class="head_album">歌手</li>
<li class="head_time">时长</li>
</ul>
</div>
<ul class="singer_list">
{% for song in songList %}
{% if forloop.counter == 1%}
<li class="song_item current flex_c">
{% else %}
<li class="song_item flex_c">
{% endif %}
<div class="song_rank flex_c">
<div class="rank_num">
<span>{{forloop.counter}}</span>
</div>
<img alt="" class="cover"
data-src="{% static 'images/re_3.jpg' %}"
src="{% static 'images/re_3.jpg' %}" lazy="loaded">
</div>
<div class="song_name flex_c">
<a title="{{song.name}}" href="/play_detail/288010178" class="name">{{song.name}}</a>
</div>
<div class="song_album">
<span title="{{song.singler.name}}">{{song.singler.name}}</span>
</div>
<div class="song_time">
<span>{{song.get_song_duration}}</span>
</div>
<div class="song_opts flex_c">
<i class="glyphicon glyphicon-plus"></i>
<i class="glyphicon glyphicon-play"></i>
<i class="glyphicon glyphicon-heart"></i>
</div>
</li>
{% endfor %}
</ul>
{% if list_num < 1 %}
<!--设置无数据内容-->
<div class="nodata flex_c">
<div class="inner">
<img src="{% static 'images/nodata.png' %}"
alt="" class="nodata_img">
<div class="tip"><p>暂无相关数据</p></div>
</div>
</div>
{% endif %}
{% if list_num > 1 %}
<div class="page">
<i class="li-page glyphicon glyphicon-menu-left notPointer"></i>
<ul>
{% for index in songList.paginator.page_range %}
{% if songList.number == index %}
<li><a href="#" class="notCursor currentPage">{{index}}</a></li>
{% else %}
<li><a href="{% url 'player:singer' index %}">{{index}}</a></li>
{% endif %}
{% endfor %}
</ul>
<i class="glyphicon glyphicon-menu-right li-page"></i>
</div>
{% endif %}
</div>
</div>
</div>
<!--歌手资料结束-->
{% endblock content %}
计算歌曲时长
表模型增加方法
单曲列表需要显示歌曲时长,但是数据库存储的是秒数,需要转化为分:秒格式。
而查询出来的查询集是一个对象格式的直接添加属性,下一步还是取不到。
解决方法:需要在表模型类中新增一个方法,去处理转换时长格式。
具体如下:
python
def get_song_duration(self):
""" 计算歌曲时长 格式 00:00 """
secs = self.duration % 60
if secs:
mins = (self.duration - secs) / 60
else:
mins = self.duration - secs / 60
return str(int(mins)) + ':' + str(secs)
模板中使用表模型方法
直接通过循环出的对象调用模型方法,需要注意不带小括号。
内容如下:
python
{% for song in songList %}
{{song.get_song_duration}}
{% endfor %}
总结
基本信息这块没什么难度,使用主键直接查询返回给模板渲染即可;
单曲列表分页还是使用Paginator来做,就时长有点小纠结,
没用过别的python框架,还是感觉数据操作这块很麻烦。