Django个人博客系统(1-5)
1.创建项目与注册app
本文采用的是最简单的创建django项目的方法,即在pycharm中创建项目时在左侧选择django即可,我们只需修改项目的名称、确定是否采用虚拟环境(推荐使用虚拟环境),然后点击create
即可。项目创建成功后,django默认的一些目录和配置文件就全部准备好了。
项目是由多个子模块组成的,每一个模块在django中就是一个app,例如我们博客项目中注册一个article
的app用来管理文章:
python manage.py startapp article
千万要注意的是,app创建成功之后一定要在settings.py
中注册,即在installed_apps
中添加app的名称,通过注册的方式来告诉django存在这么一个app。app创建的默认文件不含urls.py
,我们需要手动创建。
django的路由是多级映射的,项目目录下的urls.py
主要负责将请求发送到具体的哪个app,而app目录下的urls.py
则负责转发到哪个具体的页面。因此,app注册成功后,我们要将app的路由文件添加到项目目录下的urls.py
中:
urlpatterns = [ path('admin/', admin.site.urls), path('article/', include('article.urls', namespace='article')), # 新增代码,配置app的url ]
2.创建模型与数据迁移
django框架采用mtv模式,即模型(model)、模板(template)和视图(views)。model负责存取数据,view负责决定需要调取哪些数据,而template则负责将调取出的数据以合理的方式展现出来。
django不需要直接定义数据库表,只需定义好模型就能自动从模型映射到数据库,处理与数据相关的事务。每个模型都都是django.db.models.model
类的子类,从它继承了操作数据库需要的所有方法。每个字段都是field
类的实例,如字符字段被表示为charfield
,日期时间字段被表示为datetimefield
。
我们为article
创建一个articlepost
模型,如下:
from django.contrib.auth.models import user from django.db import models from django.utils import timezone # 博客文章 class articlepost(models.model): author = models.foreignkey(user, on_delete=models.cascade) # 文章作者,on_delete用于指定数据删除的方式 title = models.charfield(max_length=100) # 文章标题,models.charfield为字符串字段,用于保存较短的字符串 body = models.textfield() # 文章正文,textfield用于保存大量文本 created = models.datetimefield(default=timezone.now) # 文章创建时间,default=timezone.now指定在创建数据时默认写入当前的时间 updated = models.datetimefield(auto_now=true) # 文章更新时间,auto_now=true指定每次数据更新时自动写入当前时间 class meta: # 内部类,用于定义元数据 ordering = ('-created',) # ordering指定模型返回的数据的排列顺序,'-created' 表明数据应该以文章创建时间倒序排列,负号标识倒序 def __str__(self): # 定义当调用对象的 str() 方法时的返回值内容 return self.title
注意,每当对数据库进行了更改(添加、修改、删除等)操作,都需要进行数据迁移。通过运行makemigrations
命令,django会检测你对模型文件的修改,并且把修改的部分储存为一次迁移。但是此时你做的修改并没有反映到数据库中,它本质上只是个历史记录。只有通过migrate
命令才能将所有还没有执行过的迁移应用在数据库上,也就是将模型的更改同步到数据库中。
python manage.py makemigrations python manage.py migrate
模型创建成功后,如需添加后台管理,以articlepost
为例,需要在article
的admin.py
中添加如下代码:
from django.contrib import admin from .models import articlepost admin.site.register(articlepost)
对于后台管理,我们使用django自带的管理系统,使用之前需要注册一个超级用户,执行如下命令,然后输入用户名、邮箱、密码即可。
python manage.py createsuperuser
我们在浏览器中输入网址http://127.0.0.1:8000/admin/
,使用刚注册的账号登录后台管理系统,为articlepost
添加几条数据,以方便后续视图函数的调试。
3.创建视图与编写模板
django中视图的概念是「一类具有相同功能和模板的网页的集合」,其作用是处理网页发来的请求(request)并返回响应(httpresponse、http404)。django将会根据用户请求的url来选择使用哪个视图并返回渲染后的对象。我们为文章列表创建一个视图:
from django.http import httpresponse from django.shortcuts import render from .models import articlepost def article_list(request): articles = articlepost.objects.all() # 获取所有的数据对象 context = {'articles': articles} # 传递给模板的上下文 return render(request, "article/list.html", context) # render函数的作用是结合模板和上下文,并返回渲染后的httpresponse对象
视图编写完成后,需要添加到urls.py
文件中才能被调用。
from django.urls import path from .views import article_list app_name = 'article' urlpatterns = [ path('article-list', article_list, name='article-list'), ]
接下来在根目录的templates
目录下创建文件夹来存放article
的模板文件,templates
是django默认的模板文件存放目录,所谓模板就是用来展示数据的前端文件。
关于静态文件,我们首先需要注意的是它存放在根目录的static
目录下(需要手动创建),另外需要在settings.py
文件中加入以下几行代码:
static_url = '/static/' # 通常是系统自动创建 staticfiles_dirs = ( os.path.join(base_dir, "static"), )
模板中其实有很多部分是通用的,例如头部和脚注,对于这些我们可以将它们放到基类模板中,其他模板继承自基类模板。base.html
:我们在该文件中通过{% load static %}
加载静态文件,并且通过block
预留一些内容填充的位置,其他模板均继承自该文件。
<!-- 加载静态文件 --> {% load static %} <!doctype html> <html lang="zh-cn"> <head> <meta charset="utf-8"> <!-- 预留网页标题的位置 --> <title>{% block title %}{% endblock %}</title> <!-- 加载bootstrap的css文件和图标库 --> <link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.min.css' %}"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css"> </head> <body> <!-- 引入导航栏 --> {% include 'header.html' %} <!-- 预留具体内容页面的位置 --> {% block content %}{% endblock content %} <!-- 引入注脚 --> {% include 'footer.html' %} <!-- 加载bootstrap的js文件 --> <script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script> </body> </html>
header.html
<nav class="navbar navbar-expand-lg navbar-dark bg-dark"> <div class="container"> <a class="navbar-brand" href="#"> marvin's blog </a> </div> </nav>
footer.html
<footer class="py-3 bg-dark fixed-bottom"> <div class="container"> <p class="m-0 text-center text-white">copyright © www.marvin.com 2021</p> </div> </footer>
list.html
用于展示文章列表,articles
是通过视图函数传递过来的所有文章对象,我们通过for
循环依次展示它们。
{% extends "base.html" %} {% block title %}首页{% endblock %} {% block content %} <div class="container"> <div class="row mt-4"> {% for article in articles %} <div class="col-4"> <div class="card"> <div class="card-header"> <h5>{{ article.title }}</h5> <small class="text-secondary"><i class="bi bi-calendar-check"></i> 发表于 {{ article.created }}</small> </div> <div class="card-body"> <p class="card-text">{{ article.body|slice:'100' }}</p> <!-- slice:'100'是django的过滤器语法,表示取出正文的前100个字符,避免摘要太长 --> <a href="#" class="btn btn-primary">阅读本文</a> </div> </div> </div> {% endfor %} </div> </div> {% endblock %}
效果如下图所示:
4.页面跳转与参数传递
到目前为止,我们已经知道了如何创建视图以及模板,我们按照上述方法再添加一个文章详情的功能页面。视图函数如下:
def article_detail(request, id): article = articlepost.objects.get(id=id) context = {'article': article} return render(request, "article/detail.html", context)
视图函数中的id参数是django自动生成的用于索引数据表的主键(primary key),我们在写model的时候并没有写叫做id的字段。接下来我们需要将其添加到路由中:
path('article-detail/<int:id>/', article_detail, name='article-detail')
<int:id>
:django用尖括号<>定义需要传递的参数。最后是模板文件:
{% extends "base.html" %} {% block title %}文章详情{% endblock %} {% block content %} <div class="container shadow"> <div class="pt-4"> <h1>{{ article.title }}</h1> <small class="text-secondary"><i class="bi bi-calendar-check"></i> 发表于 {{ article.created }}</small> </div> <div class="mt-2 border-top pt-2"> {{ article.body }} </div> </div> {% endblock %}
详情页面完成后,我们在导航中添加首页的跳转链接,方便从详情页回到文章列表。添加内容如下:
<div class="collapse navbar-collapse"> <ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link active" aria-current="page" href="{% url 'article:article-list' %}">首页</a> </li> </ul> </div>
5.markdown代码高亮
markdown是博客中使用体验非常好的语法,添加mardown支持的方法也很简单,只需安装markdown库即可(pip install markdown
)。为了将markdown语法书写的文章渲染为html文本,我们需要修改article_detail()视图函数:
def article_detail(request, id): article = articlepost.objects.get(id=id) # 将markdown语法渲染成html样式 article.body = markdown.markdown(article.body, extensions=[ 'markdown.extensions.extra', # 包含 缩写、表格等常用扩展 'markdown.extensions.codehilite', # 语法高亮扩展 ]) context = {'article': article} return render(request, "article/detail.html", context)
然后,需要修改detail.html
中有关文章正文的部分:
<div class="mt-2 border-top py-2"> {{ article.body|safe }} </div>
django出于安全考虑,会对输出的html代码进行转义,这使得article.body
中渲染的html文本无法正常显示。|safe
的作用是表示这一段字符不需要进行转义了。
代码高亮是技术文章必不可少的部分,为此我们需要安装pygments库(pip install pygments
),然后在static
目录中新建一个md_css
目录,接着执行如下命令:
pygmentize -s monokai -f html -a .codehilite > ./static/md_css/monokai.css
执行成功后就会在md_css
目录中生成了一个monokai.css
文件,然后在base.html
中引用这个文件就大功告成了。
<link rel="stylesheet" href="{% static 'md_css/monokai.css' %}">
由于pygments的表格样式比较难看,因此我们在detail.html
中添加如下代码进行美化:
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <script> // 将表格样式替换为bootstrap表格 $('.container table').addclass('table table-bordered'); $('.container thead').addclass('thead-light'); // 为代码块添加圆角和内外边距 $('.codehilite').addclass('rounded-3 p-3 my-3'); </script>
最终效果如下图所示:
文章参考博文: