本文通过手写一个最简单的博客网站来演示 Django 的 Web 开发。
源码地址:https://github.com/wsuo/Django-blog
演示:
功能要求:
- 具有文章列表页,文章详情页;
- 文章列表页点击文章可跳转到对应详情页;
- 文章列表页具有分页功能;
- 文章详细页具有上下文章跳转;
1、创建项目
使用 PyCharm
创建一个 DJango
项目。
指定路径之后,点击 create
创建项目。
创建完成之后的项目结构:
我们采用分模块开发,所以新建一个文章的模块,取名为article
,在 Pycharm
下面找到终端程序,点击进去之后执行下面的命令:
python manage.py startapp article
这个时候我们的项目结构就发生了变化,多了一个 article
文件夹:
此时我们称 blog
为主应用程序,article
为子应用。
migrations
: 为迁移文件夹,和数据库交互用到的;admin
:是用来管理页面的;apps
:是设置应用程序的名称等信息;models
:模型,和后台数据库相关,我们在这里创建对象,数据库就可以自动的生成表;tests
:测试文件;views
:视图相关。
创建之后我们要在主程序中注册该应用,打开 settings
文件,将应用配置进去即可:
快捷创建应用:
当然也可以直接在创建项目的时候就创建一个应用,只需要在这里写应用名称就可以了,然后也不用配置那么多了, Pycharm
都帮你配置好了,直接到下一步就可以了:
2、设置路由
要想实现跳转页面的功能,肯定要设置路由,总体的路由控制都是在 urls
文件中配置的,具体到哪一个页面由 views
控制;由于我们项目是分级的,所以我们要分别配置一下路由信息,首先在子应用程序中新建一个 urls
文件,然后在主应用中的 urls
文件中引入子应用的路由。
下面检验一下路由配置是否正确。
首先创建一个首页的前端页面,然后在 views
中创建一个 index
函数,让该函数返回 index
HTML 页面。
然后设置该应用的路由信息:
然后 shift+F10
启动项目,在浏览器访问。
http://127.0.0.1:8000/blog/article/
这说明路由配置成功了,之所以你能看到这个页面,是因为我事先准备了一个 index.html
文件放在了 template
文件夹下,如上图所示,该静态页面可以访问文章顶部的链接获取。
3、创建数据库
这里我们使用 SQLite3
数据库:
- 首先创建一个实体类
Article
; - 然后将实体类迁移到数据库系统。
创建实体类的代码如上,需要在 models
文件中创建。
article_id
:文章的标题,设置为主键并且自增,如果不设置也会有一个默认的主键;title
等属性都设置成了文本类型,因为要存的数据会很大。
那么如何将文件迁移到数据库呢?
只需要执行下面两个命令即可:
python manage.py makemigrations article
python manage.py migrate
第一个命令是将自己的应用下的文件作为待迁移的文件,第二个命令是将所有的待迁移文件挂载到数据库,生成相应的表和属性,其中包括系统再带的数据库和我们自己创建的数据库。
点击右侧的 DataBase
使用 Pycharm
的插件连接数据库,定位到项目中的 db
文件,然后连接即可。
之后你就可以在控制台 愉快的 写 SQL
语句了:
我们也可以使用 Django
自带的 Admin 功能来实现通过 web
浏览器的方式来访问数据库,只需要配置一下一下的几个地方:
- 首先在主应用的
settings
文件中修改配置信息:
大概在 108
行左右:
LANGUAGE_CODE = 'zh-Hans'
TIME_ZONE = 'Asia/Shanghai'
-
然后在子应用的
admin
文件中修改:
将我们的实体类注册进去。 -
然后在终端执行命令来设置管理员的账号和密码,因为数据库肯定不是外界随便访问的。
这里我设置了用户名和密码都是admin
。
这个时候我们去访问 /admin
页面就能当问了中,因为在主应用中已经默认配置了路由信息,如下:
访问之后就是这样的效果:
登陆以后点击自己的数据库即可:
然后我们先初始化一些数据,这里的数据你可以在上面的管理页面一个一个的复制粘贴导入并保存,也可以写一个脚本自动化完成,如果你都不想的话可以直接用我 github
上面的 数据库配置文件 替换掉你的配置文件:
4、页面展示
下面将数据库中的内容展示到页面上,这里使用 路由+模板引擎 ,该模板引擎就是你平常用的模板引擎,类似于 thymeleaf、freemark
,官方文档:https://docs.djangoproject.com/en/3.0/ref/templates/builtins/。
先设置一下路由信息:
from django.urls import path
from article import views
urlpatterns = [
path('article/', views.index)
]
然后在 views 文件下编写代码:
def index(req):
articles = Article.objects.all()
return render(req, 'index.html',
{
'articles': articles,
})
前端书写代码:
<div class="body-main">
{% for article in articles %}
<div>
<h2><a href="#">{{ article.title }}</a></h2>
<p>
{{ article.content }}
</p>
</div>
{% endfor %}
</div>
然后访问 http://127.0.0.1:8000/blog/article/
发现文章已经展示出来了,请注意访问路径:
5、点击文章跳转
下面实现点击文章标题即可跳转到文章详情页面的功能。
首先修改前端代码:
<div class="body-main">
{% for article in articles %}
<div>
<h2><a href="/blog/detail/{{ article.article_id }}">{{ article.title }}</a></h2>
<p>
{{ article.content }}
</p>
</div>
{% endfor %}
</div>
注意这里使用拼接 url
的方式传入了一个 id
,我们就可以根据这个 id
来判断是那一篇文章,然后跳转到指定的页面。
那么后端怎么来接收这个参数呢?在 views
下配置如下信息:
这样就能接收到传入的 id
值了。
然后根据传入的 Id 值遍历文章列表,寻找那个 id
值对应的文章,由于我们要遍历的对象没有索引,所以我们手动加上一个索引,使用enumerate
函数遍历即可:
def get_detail_page(req, article_id):
all_article = Article.objects.all()
curr_article = None
for idx, article in enumerate(all_article):
if idx == article_id:
curr_article = article
break
return render(req, 'detail.html', {
'curr_article': curr_article,
})
最后在 detail
页面接收。
<div class="container page-header">
<h1>{{ curr_article.title }}</h1>
</div>
<div>
<p>
{{ curr_article.content }}
</p>
</div>
效果是这样的:
6、上下文切换
但是下面两个按钮还没有用到,我们想通过点击按钮即可实现上下文切换的功能。
那么我们需要在后端提供一个记录着上一篇文章和下一篇文章的字段值,只需记录 id
值即可,然后再次跳转到 detail
页面即可实现功能。
修改后端代码如下:
返回值为:当前文章的数据,下一篇文章的数据,和上一篇文章的数据。
注意一点就是如果已经到达了首页或者尾页,那么就不能再跳转了,所以进行了两个判断。
最后在页面中接收即可:
效果展示:
7、主页分页
由于文章过多,主页会很长,所以必须考虑使用分页。
这里分页使用一个 DJango
自带的工具 django.core.paginator
;
分析逻辑:
- 首先我们需要从前端获取一个
page
参数,这样我们才能之后想要第几页,可以使用GET
请求获取; - 我们需要使用分页插件来分页,记录总页数、每一页中的文章集合、当前页码等信息。
前端提供一个 page
参数,在 url 中绑定。
/blog/index/?page=1
后端通过 GET
方法获取绑定的值。
from django.core.paginator import Paginator as pG
def index(req):
articles = Article.objects.all()
p = req.GET.get('page')
p = int(p) if p else 1
pl = pG(articles, 3)
pn = pl.num_pages # 总页数
pal = pl.page(p) # 每一页中的集合
if pal.has_next():
np = p + 1
else:
np = p
if pal.has_previous():
pp = p - 1
else:
pp = p
return render(req, 'index.html',
{'articles': pal,
'cur_page': p,
'prev_page': pp,
'next_page': np,
'num': range(1, pn + 1)}
)
这里通过 pG(articles, 3)
设置页数为每页展示 3
篇文章,注意这里写死了为 3
页,后面想改变就在这里改 pl = pG(articles, 3)
。
返回给前端如下信息:
- 文章集合;
- 当前页码;
- 前一页页码;
- 后一页页码;
- 总页数(可遍历);
前端去接收这些值,代码如下:
最核心的就是使用 for
循环去遍历得到的数据,然后分别展示。
但是还有一个问题就是分页之后 区分不出来当前是第几页 ,使用模板语言调整。
参考:https://docs.djangoproject.com/en/3.0/ref/templates/builtins/
{% for n in num %}
{% if cur_page == n %}
<li><a href="?page={{ n }}" style="color: coral">{{ n }}</a></li>
{% else %}
<li><a href="?page={{ n }}">{{ n }}</a></li>
{% endif %}
{% endfor %}
这样当前页就会变成 橘色 显示。
到此为止就算是入门了,重点理解一下 项目结构 与 路由控制,后面会推出连接数据库的版本,并完善该项目为实际可用博客网站,目前 CRUD 仅仅完成了 查 的功能。