Django - 搭建博客

最近在学习Vue.js,需要后端配合返回Json,所以就顺便学习了一下Django,这里就记录一下搭建博客的全过程,作为起手式。由于之前用Thinkphp做过一个项目,所以对MVC(MTV)框架有了一点了解,Django就轻车熟路了,直接上手。这里就记个记个流水账,没学过的朋友直接照着敲就行了,敲完一定会有不少理解。

说明

  1. 资源下载地址:项目文件 前端文件
  2. 文章中的{%%}已经转义成了{%%},请自行更改。因为会和hexo的语法产生冲突,你看哈,我这里都得写成了中文的(其实是英文的),坑爹。

环境搭建

我的操作系统是Win10,IDE是VSCode。先给VSCode安装几个插件:

  • Python
  • Django Template

然后我们需要安装Python,去官网下载最新版本,一路下一步即可,我装的是Python3.7。

Python安装后我们需要安装一个Virtualenv来创建虚拟环境。为什么呀创建虚拟环境呢?因为Python是基于模块来扩展功能的,我们完成一个项目会安装许多的扩展模块,项目一多不容易管理,且容易发生冲突,所以我们需

要创建一个虚拟环境将每个项目封装起来。ctrl + ~打开终端,输入以下指令:

pip install virtualenv  #安装Virtualenv

新建一个目录,我这叫django_web,cd到目录。

virtualenv env  #创建env虚拟文件夹
env\Scripts\activate.bat #激活虚拟环境

在当前目录下新建requirements.txt文件,写入如下内容:

django
pylint
pylint-django
autopep8

django–Web开发框架,pylint–Python静态语法检测器,pylint-django– 适用于Django项目的语法检查插件,autopep8–代码格式化工具

pip install requirements.txt  #安装以上模块

创建项目

django_web目录下输入以下指令:

django-admin startproject blog  #创建blog项目

cd blog #cd到blog目录

python manage.py startapp index #创建index应用

项目&应用:

项目: 在这个项目中通俗的讲就是博客项目(blog)。一个项目中可以有许多功能独立的应用组成,最终完成整个系统。

应用: 在这个项目中通俗的讲有两个应用,分别是前台(index)后台(admin)。应用是功能相对独立的一个模块,可以移植到不同的项目中。

在VSCode中按Ctrl + Shift + P,输入工作区,点击工作区:打开工作区配置文件,查看是否含有以下内容,没有的话做适当修改。

"settings": {
"python.pythonPath": "${workspaceFolder}\\env\\Scripts\\python.exe",
"python.linting.pylintPath": "pylint",
"python.linting.pylintArgs": [
"--load-plugins", "pylint_django"
],
"python.formatting.autopep8Path": "autopep8"
}

再次按下Ctrl + Shift + P,输入Python,点击Python:选择解析器,然后点击Python3.7(virtualenv)。即使用虚拟环境中的Python解析器。

至此,项目目录结构如下:

django_web
- env #虚拟环境
- blog
-- manage.py #Django的管理工具,可以运行web服务、管理数据库等工作。
-- blog #blog项目
--- settings.py #项目配置文件
--- urls.py #将URL模式映射到应用
--- wsgi.py #项目部署
-- index #index应用
--- admin.py #默认的后台管理程序
--- apps.py #应用的相关配置。
--- models.py #模型文件(model),用于配置ORM,设计数据库
--- tests.py #单元测试
--- veiws.py #视图文件(view),用于编写功能的主要处理逻辑

创建数据库

Django默认且自带SQLite数据库,对于这个小项目,使用SQLite足够了。如果你想使用其他数据库,如MySQL,请查阅相关文档

打开index目录下的model.py,该文件用于定义数据库结构。

from django.db import models

class Article(models.Model):
title = models.CharField(max_length = 150) #文章标题
content = models.TextField() #文章正文
post_time = models.DateTimeField() #文章创建时间
views = models.IntegerField(default=0) #文章访问量,初始化为0

可以看到类名Article将作为数据库中的一张数据表,类中的每一条内容为一个字段,=后面的models的实例为字段的类型。

blog目录下执行以下指令:

python manage.py makemigrations blog  #将模型文件储存为迁移

python manage.py migrate #通过迁移创建数据库

现在,项目文件下会生成一个db.sqlite3文件,这个便是系统生成的数据库,可以使用SQLite管理工具打开。

启动默认后台管理程序

使用默认的后台管理程序,需要先创建账号。在blog目录下输入以下指令:

python manage.py createsuperuser  #创建账户
Username (leave blank to use 'fnngj'): admin #管理员帐号
Email address: 894519210@qq.com #email
Password: ******** # 密码
Password (again): ******** #重复密码
Superuser created successfully. #创建成功

接下来我们将创建好的Article数据表绑定到后台管理程序。

打开index下的admin.py文件,写入如下内容:

from django.contrib import admin
from index.models import Article

class ArticleAdmin(admin.ModelAdmin):
list_display = ['title', 'content', 'post_time', 'views']

admin.site.register(Article, ArticleAdmin)

然后在blog下输入以下指令,启动Django:

python manage.py runserver

在浏览器中输入127.0.0.1:8000/admin,输入用户名密码,进入后台管理页面。

在这里,我们可以撰写文章了,当务之急,肯定是先写个“Hello, World!”嘛。

hello,world

可以看到,Django默认配置的后台管理程序还是很方便的,虽说有点小丑,但功能还是很齐全的。没关系,我们后面会开发自己的后台管理页面。

模板渲染

数据库已经有文章内容了,这时候我们需要完成我们的前台页面。

首先在index目录下创建一个templates文件夹,这个文件夹是用来存放我们的.html文件的。在templates目录下将我们前端文件中的.html文件全拷进去。

打开veiws.py文件,输入:

from django.shortcuts import render
from index.models import Article #引入Article类,即数据库

def index(request):
articleList = Article.objects.order_by("-post_time").all() #从数据库中读出所有文章列表
return render(request, 'index.html', {'articleList': articleList}) #将文章列表渲染到index.html

def article(request, id):
article = Article.objects.get(pk=id)
return render(request, 'article.html', {'article': article})

打开index.html,将其中输出文章列表的div内容改成如下(多余的div块删了吧,只留一个就行)

<div class="container list wrap">
&#123;% for article in articleList %&#125;
<div class="content">
<h3>
<a href="\&#123;% url 'index:article' article.id %\}">{{ article.title }}</a>
</h3>
<div class="info">
<span>
<i class="fa fa-clock-o"></i>发布时间: {{ article.post_time }}</span>
<span>
<i class="fa fa-eye"></i>阅读量: {{ article.views }}</span>
</div>
{{ article.content }}
</div>
&#123;% endfor %&#125;
</div>

稍微解释一下,这个views.py就是负责将数据从数据库调出,业务逻辑处理后,渲染到前端模板(index.html)。我们对应着这两个文件看:

视图层解释

views.py读取了Article数据库中的数据,存放到articleList这个变量中,然后渲染到index.html文件。

&#123;% for article in articleList %&#125; 表示进行循环,文章有就循环几次。{{ article.title }}双括号中的数据会替换成数据库中读出的每条记录,这里就是对应文章的标题。

\&#123;% url 'index:article' article.id %\}会渲染成一条链接,链接到index应用中的article类并传入articleID,即/article/id/

同样的,我们将article.html也套入渲染标签,具体的可以参照项目文件。

路由绑定

写完模板文件后网页还不能直接访问,因为我们还没有建立对应的路由。

blog目录下的urls.py写入内容:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path('admin/', admin.site.urls), #后台的URL
path('', include('index.urls')), #index应用的URL
]

然后在index目录新建一个urls.py,写入:

from django.urls import path
from . import views #引入视图类

app_name = 'index' #定义命名空间
urlpatterns = [
path('', views.index, name='index'), #绑定index,即首页
path('article/<int:id>/', views.article, name='article'), #绑定artile,即文章页
]

这里我们用到了俩个urls.py,这样做有个好处,系统先解析到项目目录下的urls,再分发到各个应用下的urls,当应用多时,不容易发生冲突。一图以蔽之:

url分发

解释一下pathpath('article/<int:id>/', views.article, name='article')中: 第一部分为匹配URL(匹配“article/id”),<int:id>说明传入一个int类型的id参数;第二部分将匹配到的链接解析到views.py视图文件中的article类;第三部分name='article'定义的是一个别名,前面\&#123;% url 'index:article' article.id %\}中的index:article就是这个别名。

现在运行python manmage.py runserver,就可以看到页面了。

无样式首页

很丑对不对,因为我们没有引入css样式,下面介绍怎么引入静态资源。

静态资源引入

页面中的css、js、images、fonts都是静态资源,我们需要将它存放到公共目录,然后在html中动态引入。

为什么要动态引入?
一: 动态引入后,我们如需变动静态资源的位置,只需在`setting.py`中重新设置下静态资源的路径即可,不必到各个`html`中改,省事儿。二: 项目在生产环境中运行时,一般只把静态资源暴露给用户,这样有利于网站安全。

index目录中新建一个static文件夹,将前端文件中的静态资源(css、js、images、ico、fonts)全都丢进去。

由于Django默认就已经设置好了静态资源的路径,即当前应用下的static文件夹,所以我们无需另外设置。

index.html中最前面写上\&#123;% load static %\},说明我们引入了静态资源。将标签中的静态资源都改成以下格式\&#123;% static 'css/index.css' %\}。贴张图很明白:

静态资源

ps: js也要改,如果有图片也得改。

再次运行服务器,刷新下页面,是不是样式回来啦~

有样式首页

模板分离

不知道你有没有发现,我们这个项目中index.htmlarticle.html俩个文件的头部和尾部(也就是引入的静态资源部分)是一样的,不同的只是中间内容部分。我们可以建立一个公共模板页面,然后其他页面都套用这个公共页面,只更改变化的部分即可。

原因很显然,牵一发而动全身。

templates目录中新建一个base.html,它就是我们的公共模板,写入:

\&#123;% load static %\}
<!DOCTYPE html>
<html lang="zh-CN">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<link rel="stylesheet" type="text/css" href="\&#123;% static 'css/font-awesome.min.css' %\}">
<link rel="stylesheet" type="text/css" href="\&#123;% static 'css/bootstrap.min.css' %\}">
<link rel="stylesheet" type="text/css" href="\&#123;% static 'css/index.css' %\}">
<link rel="icon" href="\&#123;% static 'favicon.ico' %\}">
&#123;% block header %&#125;&#123;% endblock %&#125;
<title>zhaoo</title>
</head>

<body>
<nav class="navbar navbar-expand-md bg-dark navbar-dark">
<div class="container">
<a class="navbar-brand" href="/">zhaoo</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsibleNavbar">
<span class="navbar-toggler-icon"></span>
</button>
<!-- <div class="collapse navbar-collapse" id="collapsibleNavbar">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="/"><i class="fa fa-home"></i>&nbsp;首页</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#"><i class="fa fa-file-text"></i>&nbsp;文章</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#"><i class="fa fa-info-circle"></i>&nbsp;关于</a>
</li>
</ul>
</div> -->
</div>
</nav>
&#123;% block content %&#125;&#123;% endblock %&#125;
<footer class="footer">
<div class="container">
<ul class="link">
<li><a href="#">友情链接</a></li>
<li><a href="#">站点地图</a></li>
<li><a href="#">关于我们</a></li>
<li><a href="#">管理后台</a></li>
</ul>
<p class="copyright">Copyright© 2018-2018 | <a href="#">zhaoo</a> .AllRightsReserved</p>
</div>
</footer>
<script src="\&#123;% static 'js/jquery.min.js' %\}"></script>
<script src="\&#123;% static 'js/bootstrap.min.js' %\}"></script>
<script src="\&#123;% static 'js/index.js' %\}"></script>
<script src="\&#123;% static '/ckeditor/ckeditor/ckeditor.js' %\}"></script>
<script src="\&#123;% static '/ckeditor/ckeditor-init.js' %\}"></script>
&#123;% block footer %&#125;&#123;% endblock %&#125;
</body>

</html>

然后在index.html中我们就可以这么写了:

&#123;% extends "base.html" %&#125;
&#123;% block content %&#125;
<div class="container list wrap">
&#123;% for article in articleList %&#125;
<div class="content">
<h3>
<a href="\&#123;% url 'index:article' article.id %\}">{{ article.title }}</a>
</h3>
<div class="info">
<span>
<i class="fa fa-clock-o"></i>发布时间: {{ article.post_time }}</span>
<span>
<i class="fa fa-eye"></i>阅读量: {{ article.views }}</span>
</div>
{{ article.content }}
</div>
&#123;% endfor %&#125;
</div>
&#123;% endblock %&#125;

解释:

模板:
&#123;% block content %&#125;
&#123;% endblock %&#125;

子文件:
&#123;% extends "base.html" %&#125; //引入base.html模板
&#123;% block content %&#125;
...code... #其中变化的部分
&#123;% endblock %&#125;

子文件中&#123;% block content %&#125;&#123;% endblock %&#125;块包围的内容就是不同的部分,系统解析时会动态插入模板中,最后生成一个个页面。

做到这一步,我们的博客项目就已经基本成型了,前台是我们自己写的,后台是Django自带的。

后台管理页面美化

这部分开始都是一些无关紧要的优化,做不做随意。

安装Mdeditor富文本编辑器

查看评论