最近在学习Vue.js,需要后端配合返回Json,所以就顺便学习了一下Django,这里就记录一下搭建博客的全过程,作为起手式。由于之前用Thinkphp做过一个项目,所以对MVC(MTV)框架有了一点了解,Django就轻车熟路了,直接上手。这里就记个记个流水账,没学过的朋友直接照着敲就行了,敲完一定会有不少理解。
说明
- 资源下载地址:项目文件 前端文件
- 文章中的
{%
和%}
已经转义成了{%
和%}
,请自行更改。因为会和hexo
的语法产生冲突,你看哈,我这里都得写成了中文的(其实是英文的),坑爹。
环境搭建
我的操作系统是Win10,IDE是VSCode。先给VSCode安装几个插件:
然后我们需要安装Python,去官网下载最新版本,一路下一步即可,我装的是Python3.7。
Python安装后我们需要安装一个Virtualenv来创建虚拟环境。为什么呀创建虚拟环境呢?因为Python是基于模块来扩展功能的,我们完成一个项目会安装许多的扩展模块,项目一多不容易管理,且容易发生冲突,所以我们需
要创建一个虚拟环境将每个项目封装起来。ctrl + ~
打开终端,输入以下指令:
新建一个目录,我这叫django_web
,cd到目录。
virtualenv 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
cd blog
python manage.py startapp 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 -- blog --- settings.py --- urls.py --- wsgi.py -- index --- admin.py --- apps.py --- models.py --- tests.py --- veiws.py
|
创建数据库
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)
|
可以看到类名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
def index(request): articleList = Article.objects.order_by("-post_time").all() return render(request, 'index.html', {'articleList': articleList})
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"> {% for article in articleList %} <div class="content"> <h3> <a href="\{% 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> {% endfor %} </div>
|
稍微解释一下,这个views.py
就是负责将数据从数据库调出,业务逻辑处理后,渲染到前端模板(index.html
)。我们对应着这两个文件看:
视图层解释
views.py
读取了Article
数据库中的数据,存放到articleList
这个变量中,然后渲染到index.html
文件。
{% for article in articleList %}
表示进行循环,文章有就循环几次。{{ article.title }}
双括号中的数据会替换成数据库中读出的每条记录,这里就是对应文章的标题。
\{% url 'index:article' article.id %\}
会渲染成一条链接,链接到index
应用中的article
类并传入article
的ID
,即/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分发
解释一下path
,path('article/<int:id>/', views.article, name='article')
中: 第一部分为匹配URL(匹配“article/id”),<int:id>
说明传入一个int类型的id参数;第二部分将匹配到的链接解析到views.py
视图文件中的article
类;第三部分name='article'
定义的是一个别名,前面\{% 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
中最前面写上\{% load static %\}
,说明我们引入了静态资源。将标签中的静态资源都改成以下格式\{% static 'css/index.css' %\}
。贴张图很明白:
静态资源
ps: js也要改,如果有图片也得改。
再次运行服务器,刷新下页面,是不是样式回来啦~
有样式首页
模板分离
不知道你有没有发现,我们这个项目中index.html
和article.html
俩个文件的头部和尾部(也就是引入的静态资源部分)是一样的,不同的只是中间内容部分。我们可以建立一个公共模板页面,然后其他页面都套用这个公共页面,只更改变化的部分即可。
在templates
目录中新建一个base.html
,它就是我们的公共模板,写入:
\{% 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="\{% static 'css/font-awesome.min.css' %\}"> <link rel="stylesheet" type="text/css" href="\{% static 'css/bootstrap.min.css' %\}"> <link rel="stylesheet" type="text/css" href="\{% static 'css/index.css' %\}"> <link rel="icon" href="\{% static 'favicon.ico' %\}"> {% block header %}{% endblock %} <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> </nav> {% block content %}{% endblock %} <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="\{% static 'js/jquery.min.js' %\}"></script> <script src="\{% static 'js/bootstrap.min.js' %\}"></script> <script src="\{% static 'js/index.js' %\}"></script> <script src="\{% static '/ckeditor/ckeditor/ckeditor.js' %\}"></script> <script src="\{% static '/ckeditor/ckeditor-init.js' %\}"></script> {% block footer %}{% endblock %} </body>
</html>
|
然后在index.html
中我们就可以这么写了:
{% extends "base.html" %} {% block content %} <div class="container list wrap"> {% for article in articleList %} <div class="content"> <h3> <a href="\{% 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> {% endfor %} </div> {% endblock %}
|
解释:
模板: {% block content %} {% endblock %}
子文件: {% extends "base.html" %} {% block content %} ...code... #其中变化的部分 {% endblock %}
|
子文件中{% block content %}{% endblock %}
块包围的内容就是不同的部分,系统解析时会动态插入模板中,最后生成一个个页面。
做到这一步,我们的博客项目就已经基本成型了,前台是我们自己写的,后台是Django自带的。
后台管理页面美化
这部分开始都是一些无关紧要的优化,做不做随意。
安装Mdeditor富文本编辑器