Bootstrap

25-Django项目实战(3)

1 定义路由列表

项目中设置了6个项目应用,每个项目应用实现不同的网页功能,在开发网页功能之前,首先为各个项目应用设置路由空间,再由各个项目应用的urls.py定义具体的路由信息。打开music的urls.py定义项目的路由列表,在路由列表中定义各个项目应用的路由空间。

代码如下:

from django.contrib import admin
from django.urls import path, re_path, include
# serve() 视图可以用来为你给它的任何目录提供服务。
from django.views.static import serve
from django.conf import settings

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('index.urls')),
    path('ranking.html', include('ranking.urls')),
    path('play/', include('play.urls')),
    path('comment/', include('comment.urls')),
    path('search/', include('search.urls')),
    path('user/', include('user.urls')),
    # 定义静态资源的路由信息
    re_path('static/(?P<path>.*)', serve, {'document_root': settings.STATIC_ROOT}, name='static'),
    # 定义媒体资源的路由信息
    re_path('media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}, name='media'),
]

上述的路由空间以最简单的方式定义,因为项目的网页数量不多,所以路由空间可以无须设置参数namespace。

由于项目的配置文件settings.py设置媒体资源文件夹media,因此还需要在路由对象urlpatterns中设置媒体资源的路由信息。

2 编写公用模板

在模板文件夹templates中编写公用模板文件base.html,该文件用于定义整个音乐网站平台的网页结构。打开公用模板文件base.html,编写以下网页代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="renderer" content="webkit">
    <meta name="keywords" content="">
    <meta name="description" content="">
    <title>我的音乐</title>
    {% block link %}{% endblock %}
</head>
<body>
    {% block body %}{% endblock %}
    <div class="footer">
    <div class="copyright">
        <p>网站数据信息来源于网络</p>
    </div>
    </div>
</body>
</html>

模板文件base.html定义了模板继承接口link和body,每个接口负责实现不同的功能。接口link用于引入css样式文件、JavaScript脚本文件等静态文件;接口body用于编写网页内容。

3 网站首页

网站首页是整个网站的主页面,从网站的需求设计来看,首页一共实现7个功能:歌曲搜索、轮播图、音乐分类、热门歌曲、新歌推荐、热门搜索个热门下载。

网站首页在index中实现,首先在index的urls.py中定义路由index,路由的HTTP请求由视图函数indexView接收和处理,路由index的定义如下所示:

from django.urls import path
from .views import *

urlpatterns = [
    path('', indexView, name='index'),
]

下一步在index的views.py中定义视图函数indexView,视图函数indexView主要实现模型Dynamic、Label和Song的数据查询。

代码实现如下:

from django.shortcuts import render
from .models import *


def indexView(request):
    songDynamic = Dynamic.objects.select_related('song')
    # 热搜歌曲
    searchs = songDynamic.order_by('-search').all()[:8]
    # 音乐分类
    labels = Label.objects.all()
    # 热门歌曲
    popular = songDynamic.order_by('-plays').all()[:10]
    # 新歌推荐
    recommend = Song.objects.order_by('-release').all()[:3]
    # 热门搜索、热门下载
    downloads = songDynamic.order_by('-download').all()[:6]
    tabs = [searchs[:6], downloads]
    return render(request, 'index.html', locals())

视图函数indexView执行了6次数据查询,一共生成了7个变量,说明如下:

(1)变量songDynamic使用select_related方法实现模型Dynamic和Song的数据查询,由模型Dynamic作为查询主体,通过外键字段song关联模型Song的数据。

(2)变量searchs用于对变量songDynamic的数据对象执行数据排序查询,以模型字段search进行降序排列,并且只获取前8行的数据信息。

(3)变量labels用于查询模型Label的全部数据。

(4)变量popular用于对变量songDynamic的数据对象执行数据排序查询,以模型字段plays进行降序排列,并且只获取前10行的数据信息。

(5)变量recommend用于查询模型Song的数据,以模型字段release进行降序排列,只获取前3行的数据信息。

(6)变量downloads用于对变量songDynamic的数据对象执行数据排序查询,以模型字段download进行降序排列,并且只获取前6行的数据信息。

(7)变量tabs将变量searchs的前6行数据和变量downloads的数据放置在同一个列表中。

模板文件index.html从视图函数indexView中获取变量searchs、labels、popular、recommend和tabs,这些变量将作为模板上下文,并由模板引擎进行解析处理,最终在浏览器上生成网页内容。

我们在模板文件index.html中编写以下代码:

{% extends "base.html"  %}
{% load static %}

{# ① #}
{% block link %}
<link rel="shortcut icon" href="{% static "favicon.ico" %}">
<link rel="stylesheet" href="{% static "css/common.css" %}">
<link rel="stylesheet" href="{% static "css/index.css" %}">
{% endblock %}

{% block body  %}
<body class="index">
	<div class="header">
        {# ② #}
		<a href="/" class="logo"><img src="{% static "image/logo.png" %}"></a>
		<div class="search-box">
	    <form id="searchForm" action="{% url 'search' 1 %}" method="post">
        {% csrf_token %}
	        <div class="search-keyword">
	            <input name="kword" type="text" class="keyword" maxlength="120">
	        </div>
	        <input id="subSerch" type="submit" class="search-button" value="搜 索">
	    </form>
	    <div id="suggest" class="search-suggest"></div>
  		<div class="search-hot-words">
			{% for s in searchs  %}
				<a target="play" href="{% url 'play' s.song.id %}">{{ s.song.name }}</a>
			{% endfor  %}
  		</div>
  	</div>
	</div>
	<div class="nav-box">
    <div class="nav-box-inner">
        {# ③ #}
        <ul class="nav clearfix">
            <li><a href="{% url 'index' %}">首页</a></li>
            <li><a href="{% url 'ranking' %}" target="_blank">歌曲排行</a></li>
            <li><a href="{% url 'home' 1 %}" target="_blank">用户中心</a></li>
        </ul>
        <div class="category-nav">
            <div class="category-nav-header">
                <strong><a href="javascript:;" title="">音乐分类</a></strong>
            </div>
            <div class="category-nav-body">
                <div id="J_CategoryItems" class="category-items">
                {% for l in labels  %}
                    <div class="item" data-index="1"><h3>
                        <a href="{% url 'ranking' %}?type={{ l.id }}">{{ l.name }}</a></h3>
                    </div>
                {% endfor  %}
                </div>
            </div>
        </div>
    </div>
	<div class="wrapper clearfix">
		<div class="main">
			<div id="J_FocusSlider" class="focus">
				<div id="bannerLeftBtn" class="banner_btn"></div>
				<ul class="focus-list f_w">
                    <li class="f_s"><a target="play" href="{% url 'play' 12 %}" class="layz_load" >
                        <img data-src="{% static '/image/datu-1.jpg' %}"  width="750" height="275"></a>
                    </li>
					<li class="f_s"><a target="play" href="{% url 'play' 13 %}" class="layz_load" >
                        <img data-src="{% static '/image/datu-2.jpg' %}"  width="750" height="275"></a>
                    </li>
				</ul>
				<div id="bannerRightBtn" class="banner_btn"></div>
			</div>
		</div>
		<div class="aside">
            {# ④ #}
			<h2>热门歌曲</h2>
			<ul>
				{% for p in popular %}
					<li><span>{{ forloop.counter }}</span>
                        <a target="play" href="{% url 'play' p.song.id %}">{{ p.song.name }}</a>
                    </li>
				{% endfor  %}
			</ul>
		</div>
	</div>
	<div class="today clearfix">
		<div class="today-header">
            <i></i>
            {# ⑤ #}
			<h2>新歌推荐</h2>
		</div>
		<div class="today-list-box slide">
			<div id="J_TodayRec" class="today-list">
				<ul>
                {% for r in recommend %}
                    <li>
                    <a class="pic layz_load pic_po" target="play" href="{% url 'play' r.id %}" >
                        <img data-src="{{ r.img.url }}"  ></a>
                    <div class="name">
                        <h3><a target="play" href="{% url 'play' r.id %}" >{{ r.name }}</a></h3>
                        <div class="singer"><span>{{ r.singer }}</span></div>
                        <div class="times">发行时间:<span>{{ r.release |date:"Y-m-d" }}</span></div>
                    </div>
                    <a target="play" href="{% url 'play' r.id %}" class="today-buy-button" >去听听></a>
                    </li>
                {% endfor  %}
				</ul>
			</div>
		</div>
	</div><!--end today-->
	<div class="section">
		<ul id="J_Tab" class="tab-trigger">
        {# ⑥ #}
	  	<li data-cur="0" class="current t_c">热门搜索</li>
        <li data-cur="1" class="t_c">热门下载</li>
		</ul>
		<div class="tab-container">
	    <div id="J_Tab_Con" class="tab-container-cell">
            {% for tab in tabs %}
                {% if forloop.first %}
                    <ul class="product-list clearfix t_s current">
                {% else %}
                    <ul class="product-list clearfix t_s" style="display:none;">
                {% endif %}
                    {% for item in tab %}
                    <li>
                        <a target="play" href="{% url 'play' item.song.id %}" class="pic layz_load pic_po" >
                            <img data-src="{{ item.song.img.url }}" ></a>
                        <h3><a target="play" href="{% url 'play' item.song.id %}" >{{ item.song.name }}</a></h3>
                        <div class="singer"><span>{{ item.song.singer }}</span></div>
                        {% if tabs.0  == tab %}
                        <div class="times">搜索次数:<span>{{ item.search }}</span></div>
                        {% else %}
                        <div class="times">下载次数:<span>{{ item.download }}</span></div>
                        {% endif %}
                    </li>
                    {% endfor %}
                    </ul>
            {% endfor %}
        </div>
        </div>
    </div><!--end section-->
	</div>
	<script data-main="{% static "js/index.js" %}" src="{% static "js/require.js" %}"></script>
</body>
{% endblock %}

模板文件index.html实现首页的歌曲搜索、轮播图、音乐分类、热门歌曲、新歌推荐、热门搜索和热门下载,上述代码中设有标注 ① - ⑥ ,每个标注实现的功能说明如下:

(1)标注①重写模板继承接口link,引入网站首页所需的CSS样式文件,实现网页的功能布局

(2)标注②一共实现了3个网页功能:调用静态文件logo.png生成网站logo;使用HTML语言编写网页表单,生成歌曲搜索框,表单以POST请求方式提交到路由search(歌曲搜索页)中;在歌曲搜索框下方使用模板上下文searchs生成热搜歌曲,每首歌曲可以跳转到歌曲播放页面。

(3)标注③实现了导航栏、音乐分类和轮播图功能。导航栏设置了“首页”“歌曲排行”和“用户中心”链接;音乐分类由模板上下文labels提供数据内容,单击某个音乐分类即可查看该分类的歌曲排行榜;轮播图调用静态文件

datu-1.jpg和datu-2.jpg,并且单击图片可以播放相应的歌曲。

(4)标注④遍历模板上下文popular生成热门歌曲,每次遍历的数据对象为p,其中forloop.counter用于获取当前遍历的次数,从1开始计算;p.song.id用于获取模型Song的字段id;p.song.name用于获取模型Song的字段name。

(5)标注⑤遍历模板上下文recommend生成新歌推荐,每次遍历的数据对象为r,从r对象中输出歌曲名称、发布时间、歌曲封面的歌手信息,每首歌曲设置了播放链接(歌曲播放页)。其中r.img.url用于获取模型Song的字段img的文件路径,模型字段img为FileField类型,该字段类型定义了url方法获取文件的路径地址。

(6)标注⑥遍历模板上下文tabs生成热门搜索和热门下载,模板文件上下文tabs通过嵌套循环可以生成不同的网页功能,这种代码编写方式在开发过程中较为常用。

;