今天的目标是将先前存储在数据库中的数据,呈现在网页的前端内容中。
首先是一个效果测试:主要涉及了在应用中的视图函数的编写以及配置url解析,和一个简单的前端文件cd_list.html。大致结构如下图所示:
数据库内容的前端显式呈现(test)
视图函数的编写 view.py
from django.shortcuts import render, get_object_or_404
from .models import CD
def cd_list(request):
cds = CD.objects.all()
return render(request, 'music/cd_list.html', {'cds': cds})
cd_list这个视图函数主要是针对呈现一个页面上的CD表的功能
- cds:通过CD.objects.all()查询到的结果集
前端文件的编写 cd_list.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Album List</title>
</head>
<body>
<h1>Album List</h1>
<ul>
{% for cd in cds %}
<li>
<img src="{{ cd.cover_image }}" alt="{{ cd.name }}">
<strong>{{ cd.name }}</strong>
<p>{{ cd.info }}</p>
</li>
{% endfor %}
</ul>
</body>
</html>
cd_list.html实现的是一个简单的前端效果,如下图所示:
其中{% for cd in cds %}
- cds:就是我们在views视图中定义的查询到的结果集
- cd:相当于对cds这个结果集的一个实例化,从而进行下面针对每一个cd的前端排布
- {% for cd in cds %}...{% endfor %}相当于一个循环,遍历cds集中的每一个cd元素
url的配置 urls.py
创建完一个视图函数,我们需要进行url配置,确保url路径与视图函数之间的映射关系
针对我们刚刚创建的视图函数,配置url
from django.urls import path
from . import views
app_name = 'music'
urlpatterns = [
path('', views.cd_list, name='cd_list'),
#path('<int:cd_id>/', views.cd_detail, name='cd_detail'),
]
最后记住要在项目project的urls.py中也配置对应的应用的url
数据库内容的前端显式呈现(final)
通过先前的效果图我们可以看出简单的html文件只能呈现简单的排版,和网页这种排版还是有些差距的,下面我们就需要通过网页的首页html来学习它的html文件
同样,拿到了小伙伴爬到的cd_page_source的html后,进行一个找相同的操作,找到这个cd列表主题的相同之处,可以将它提取成一个通用的模板
下图为网页中用于陈列一张cd的通用的模板:
<article class="excerpt excerpt-titletype">
<div class="focus">
<a class="thumbnail" href="https://www.0daydown.com/08/2493759.html">
<img alt="VA - Summer Hits Only 2024" class="lazy" data-src="https://www.0daydown.com/wp-content/uploads/2024/07/5uke427kjLQhLBt2GF1hwaltKlA6hLFl-180x180.jpg" src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20180%20180'%3E%3C/svg%3E"/>
</a>
</div>
<header>
<h2>
<a href="https://www.0daydown.com/08/2493759.html" title="VA – Summer Hits Only 2024 - 0DayDown">
VA – Summer Hits Only 2024
</a>
</h2>
</header>
<p>
<span class="muted">
<i class="icon-user icon12">
</i>
<a href="https://www.0daydown.com/author/sanet-music">
Music
</a>
</span>
<span class="muted date">
<i class="icon-time icon12">
</i>
6小时前
</span>
<span class="muted">
<i class="icon-comment icon12">
</i>
<a href="https://www.0daydown.com/08/2493759.html#respond">
0评论
</a>
</span>
</p>
<p class="note">
Album PreviewMp3 320 kbps | 57:53 | 133 MbElectronic, House, Dance
</p>
</article>
之后,我们将这套模板放到一个针对cds中每一个对象的循环中{% for cd in cds %}...{% endfor %}
并且将其中实时扒取的一些信息替换成数据库中的信息例如{{cd.name}},{{cd.cover_image}}等等
{% for cd in cds %}
<article class="excerpt excerpt-titletype">
<div class="focus">
<a class="thumbnail" href="https://www.0daydown.com/08/2493759.html">
<img src="{{ cd.cover_image }}" alt="{{ cd.name }}">
</a>
</div>
<header>
<h2>
<a href="https://www.0daydown.com/08/2493759.html" title="{{ cd.name }}">
{{ cd.name }}
</a>
</h2>
</header>
<p>
<span class="muted">
<i class="icon-user icon12">
</i>
<a href="https://www.0daydown.com/author/sanet-music">
Music
</a>
</span>
<span class="muted date">
<i class="icon-time icon12">
</i>
6小时前
</span>
<span class="muted">
<i class="icon-comment icon12">
</i>
<a href="https://www.0daydown.com/08/2493759.html#respond">
0评论
</a>
</span>
</p>
<p class="note">
{{ cd.info }}
</p>
</article>
{% endfor %}
页面跳转
进度比想象的要快,上午实现了前端样式的复刻,因此下午开始研究网页跳转。
一提到网页之间的链接,第一个想到的就是url跳转,因此这部分的重点其实是建立好页面url链接以及形成一个所有cd通用的详情页面模板(并能够通过cd.id的属性去索引)
建立url链接
首先我们要搞清的问题是:什么动作触发跳转?从哪里跳转?跳转到哪里?
- 什么动作出发跳转?
当我们参开了页面的html设计后,会发现这三个部分有超链接的跳转,我准备先做点击CD名称跳转到CD详情这个效果。
2.从哪里跳转?
从哪里跳转:在cd_list.html中的CD名称这段段落中设置href超链接跳转,跳转到cd对象的id相应的cd_detail文件上
针对这个跳转链接,在下一个模块中介绍。
3.跳转到哪里?
跳转到哪里:为了展示CD详情页,我们需要在music的视图函数中增加cd_detail的视图函数、配置url、在templates中添加cd_detail的html模板。
def cd_detail(request, cd_id):
cd = CD.objects.get(id=cd_id)
return render(request, 'music/cd_detail.html', {'cd': cd})
这个视图函数与先前我们建立的cd_list的视图函数有所不同,它添加了cd的id唯一标识
通过这个唯一标识我们就可以实现针对每一张CD,在数据库中通过cd_id查询,跳转到他们一一对应的详情页面中
urlpatterns = [
path('', views.cd_list, name='cd_list'),
path('<int:cd_id>/', views.cd_detail, name='cd_detail'),
]
添加cd_detail的url:‘<int:cd_id>/’的意思是将/前的内容转换成int型的cd_id数据赋值,作为cd_id参数传递给视图函数cd_detail。例如下图,就会将19转换成整数19,传给视图函数。
建立cd_detail通用模板
这部分的工作和前一天建立cd_list模板的工作相同,相比更加地简单,因为一张页面值对应一张cd,因此主体都不需要太大的变更。
问题小结
- 针对同一个对象(cd)我想要增加它的属性应该怎么做?
首先,昨天我收到了小伙伴发来的第一份json文件,cds.json。
其中包括了name、cover_image、info字段的信息
现在我要研究的针对某一张CD专辑的详情页面多了description和tracklist的信息,因此在数据库里一定是将这两项信息通过索引添加到原来的数据库对象中是最方便管理的,因此采用了通过cd.name这个属性来索引,锁定添加对象:在于import_cds.py同级的目录中添加更新数据的独立脚本update_cd_data.py,下面直接上代码
import os
import django
import json
# 设置 Django 环境变量
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ZeroDays.settings')
# 初始化 Django
django.setup()
from music.models import CD # 确保使用你的实际应用和模型路径
def update_cd_data():
with open('inner_cd_data.json', 'r', encoding='utf-8') as f:
inner_cd_data = json.load(f)
for inner_cd in inner_cd_data:
# 使用 cd name 匹配并更新现有记录
try:
cd = CD.objects.get(name=inner_cd['name'])
cd.description = inner_cd.get('description', cd.description)
cd.tracklist = inner_cd.get('tracklist', cd.tracklist)
cd.save()
print(f'Successfully updated CD: {cd.name}')
except CD.DoesNotExist:
print(f'CD not found: {inner_cd["name"]}')
if __name__ == '__main__':
update_cd_data()
独立脚本已经写好,在执行python update_cd_data.py之前,要确保更新了模型的定义并且完成模型的迁移
模型定义增加description和tracklist字段,这两个字段都设置了允许为空,以防止爬取到的数据这部分出现无内容的情况出错。
模型迁移:永恒不变的两句话 python manage.py makemigrations/python manage.py migrate
只要对模型定义有更改,就记得执行这两句话
万事俱备(当然将小伙伴新发过来的内页json文件inner_cd_data.json记得加载到目录里)然后就可以执行python update_cd_data.py的命令了,数据库更新见下图:
2.大段文本中存在\n换行,但作为TextField类型字段定义时,在页面上显示时换行不显示怎么办?
这里可以添加在调用语句中添加linebreaks,例如{{cd.tracklist}}改为{{cd.tracklist|linebreaks}}