博客首页
django 框架的工作流程已经大致了解了,接下来就是真正的完成博客首页
博客模板
django 的优点之一就是将模板(Templates)独立出来,而本博客的模板是我自己使用Bootstrap
框架编写的,完整代码我放在了github上,只是简单实现博客的部分功能。将其clone
到本地以供使用。
安装
# 选择一个目录放置模板源文件,进入目录
$ git clone https://github.com/fbckf/blog-template.git
Cloning into 'blog-template'...
remote: Counting objects: 42, done.
remote: Total 42 (delta 0), reused 0 (delta 0), pack-reused 42
Unpacking objects: 100% (42/42), done.
Checking connectivity... done.
clone
到本地之后,目录中会多出一个blog-template
目录,里面就是博客模板的源文件。
# 查看 blog-template/ 目录结构
$ tree blog-template
blog-template
├── article.html
├── category.html
├── css
│ ├── base.css
│ ├── bootstrap.min.css
│ ├── bootstrap.min.css.map
│ ├── font-awesome.css
│ └── font-awesome.min.css
├── fonts
│ ├── FontAwesome.otf
│ ├── fontawesome-webfont.eot
│ ├── fontawesome-webfont.svg
│ ├── fontawesome-webfont.ttf
│ ├── fontawesome-webfont.woff
│ └── fontawesome-webfont.woff2
├── img
│ ├── 1.jpg
│ ├── 2.jpg
│ ├── 3.jpg
│ ├── 4.jpg
│ ├── carousel1.jpg
│ ├── carousel2.jpg
│ └── carousel3.jpg
├── index.html
├── js
│ ├── base.js
│ ├── bootstrap.min.js
│ ├── bootstrap.min.js.map
│ ├── jquery-3.2.1.min.js
│ └── popper.min.js
└── README.md
index.html
博客首页article.html
文章详情页面category.html
类别页面css/
存放 css 文件fonts/
存放 Font Awesome 图标字体 文件img/
存放 图片资源js/
存放 js 文件
预览
首页
修改模板
原先的首页模板只是简单编写的一个 html 文件,现在把它替换成新的的博客首页。
$ cp index.html ~/fbckf/templates/blog/
刷新页面,发现没有显示出预计的效果
按F12
查看报错信息
...
Failed to load resource: the server responded with a status of 404 (Not Found)
base.css
Failed to load resource: the server responded with a status of 404 (Not Found)
font-awesome.css
Failed to load resource: the server responded with a status of 404 (Not Found)
font-awesome.min.css
Failed to load resource: the server responded with a status of 404 (Not Found)
jquery-3.2.1.min.js
Failed to load resource: the server responded with a status of 404 (Not Found)
base.js
Failed to load resource: the server responded with a status of 404 (Not Found)
bootstrap.min.js
Failed to load resource: the server responded with a status of 404 (Not Found)
base.js
...
原因是静态文件加载错误,静态文件与模板文件的相对位置发生改变,原先的加载路径无法加载到文件,所以无法现实样式效果
静态文件
django 中,处理静态文件和模板文件差不多,都是放到指定的目录集中管理。在 blog
应用目录中创建static/blog/
目录用以存放应用自身的静态文件,之后将博客模板的静态文件复制到static/blog/
目录中
# 在 blog/ 目录中创建目录
$ mkdir static
$ mkdir static/blog
# 将静态文件复制到 blog/static/blog/ 目录中
$ cp -R css js img fonts ~/fbckf/blog/static/blog
django 会自动在应用目录下搜索静态文件,也可以将公共的静态文件分离出来单独存放,只需在 settings.py
中指定路径即可
# fbckf/settings.py
...
# 静态文件的 url 映射
STATIC_URL = '/static/'
# 部署网站时指定的收集静态文件的路径
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
# 在配置文件最末尾添加 STATICFILES_DIRS 列表,在其中添加静态文件路径
# 注意 STATICFILES_DIRS 中路径不可与 STATIC_ROOT 一致
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'blog/static'),
]
django 在加载静态文件时,会在STATICFILES_DIRS
列表中的目录下搜索目标文件进行加载,这里指定的目录是~/fbckf/blog/static/
。
在模板文件中,原本加载静态文一般是使用src
属性,如<link href="css/bootstrap.min.css" rel="stylesheet">
或者<script src="js/jquery-3.2.1.min.js"></script>
等。而在 django 中,则要用到 模板标签 {% %}
。
<!-- fbckf/templates/blog/index.html -->
<!-- 原首页源文件 -->
...
<!-- Bootstrap -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/base.css" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="css/font-awesome.css">
<link rel="stylesheet" type="text/css" href="css/font-awesome.min.css">
...
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="js/jquery-3.2.1.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="js/bootstrap.min.js"></script>
<!-- myjq -->
<script src="js/base.js"></script>
...
<!-- fbckf/templates/blog/index.html -->
<!-- 使用模板标签 -->
...
<!-- Bootstrap -->
<link href="{% static 'blog/css/bootstrap.min.css' %}" rel="stylesheet">
<link href="{% static 'blog/css/base.css' %}" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="{% static 'blog/css/font-awesome.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'blog/css/font-awesome.min.css' %}">
...
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="{% static 'blog/js/jquery-3.2.1.min.js' %}"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="{% static 'blog/js/bootstrap.min.js' %}"></script>
<!-- myjq -->
<script src="{% static 'blog/js/base.js' %}"></script>
...
修改完成之后再刷新页面,可以看到静态文件已经加载成功,样式效果也出来了。
首页数据
之前编写的的视图函数中,只获取了指定的一篇文章,然而首页中显示的文章显然不止一篇,所以需要对视图函数进行修改。
文章列表
# blog/views.py
from django.shortcuts import render
from .models import Category, Article
def index(request):
# 之前使用 get() 方法只是返回符合指定条件的文章
# 而 all() 方法则返回所有的文章,返回的对象是一个QuerySet类型数据
article_list = Article.objects.all()
# 同样的方法获取所以类别
category_list = Category.objects.all()
# 将 article_list 和 category_list 放到字典中,将该字典传递给模板
context = {
'article_list': article_list,
'category_list': category_list
}
return render(request, 'blog/index.html', context=context)
再修改模板文件,显示文章数据
<!-- fbckf/templates/blog/index.html -->
...
<!-- blog-content -->
...
<div class="row">
<div class="blog-main col-sm-8">
{% for article in article_list %}
<div class="jumbotron bg-light">
<h1 class="display-4">{{ article.title }}</h1>
<p class="lead">{{ article.abstract }}</p>
<hr class="my-4">
<p class="text-muted">{{ article.create_time }}</p>
<a href="#" class="btn btn-dark btn-lg" role="button">Read more</a>
</div>
{% empty %}
<div class="jumbotron bg-light">
<p class="lead">暂无文章,敬请期待!</p>
</div>
{% endfor %}
</div>
...
在模板文件中,可以找到 `` 这个注释,在这个注释之后找到
<div class="container content">
标签和他的子标签<div class="row">
,如上所示。而每一篇文章都包含在一个<div class="jumbotron bg-light">
标签中使用
{% for %}
模板标签循环遍历article_list
列表,并赋值给article
变量,每一个article
都是一个对象(Article类的实例),{{ article.title }}
就是调用title
属性。{% empty %}
表示当article_list
为空是执行标签中的代码。{% endfor %}
是{% for %}
模板标签的结束标签
分类列表
分类列表中需要两个数据,第一个是分类名称,第二个是分类下的文章数量,因为之前没有考虑到文章数量,所以现在要修改数据模型,在 category
模型中加入 article_count
字段来存储文章数量这一数据。
# blog/models.py
...
class Category(models.Model):
name = models.CharField(max_length=20, unique=True)
instructions = models.TextField(max_length=100, default="")
# 添加文章数量这一字段,该字段只能是正整数,默认为零
article_count = models.PositiveIntegerField(default=0)
def __str__(self):
return self.name
...
修改完模型之后,需要进行数据库迁移,更改数据库中的结构
$ python manage.py makemigrations
Migrations for 'blog':
blog/migrations/0002_category_article_count.py
- Add field article_count to category
$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
在数据库表 category
中增加了文章数量的字段之后,还没有真正完成。现在只是增加了这个字段,但是还没有去更新它,用户也不可能每次在增加文章之后,手动的去更新这个字段,所以还需要让它能够自动的去更新该字段的值。
办法有很多,这用的是最简单的一种。每次在刷新首页时更新 article_count
字段
# blog/views.py
...
def index(request):
...
category_list = Category.objects.all()
for category in category_list:
# 使用 filter() 将各个分类下的文章筛选出来,再使用 count() 方法获取数量
count = Article.objects.all().filter(category=category).count()
# 之后更新字段
category.article_count = count
category.save()
...
更改保存,之后每次用户刷新首页,都会更新文章所属类别的 article_count
字段,这个方法简单,但是效率却不高
<!-- templates/blog/index.html -->
...
<div class="sidebar-module">
<h4>分类</h4>
<ul class="list-group">
{% for category in category_list %}
<li class="list-group-item d-flex justify-content-between align-items-center">
<a href="category.html">{{ category.name }}</a>
<span class="badge badge-light badge-pill">{{ category.article_count }}</span>
</li>
{% empty %}
<li class="list-group-item d-flex justify-content-between align-items-center">
暂无分类
</li>
{% endfor %}
</ul>
</div>
...
在 <div class="row">
标签内找到 <h4>分类</h4>
这一标签,修改之后的 <ul>
标签,显示分类和分类下的文章数量。
登陆后台管理系统,添加一个新的文章进行测试,添加完成之后刷新博客首页
文章列表和分类列表都正确的显示出数据
总结
博客首页的大概轮廓已经搭建完成,但是还有一些细节部分还需要调整,另外分页和搜索功能放到后面完成。