项目描述
开发环境:PyCharm、python3.7、MySQL5.5
使用技术:服务端是使用Flask开发的,前端是使用的Layui和Markdown编辑器所实现的。
项目包含功能如下:
-
注册:注册账号
-
登录:通过账号密码进行登录
-
写博客:写博客采用的Markdown编辑器完成的。可以发布自己的博客 -
我的博客:查看自己发布的博客并对其管理 -
我的评论:查看自己的所有评论并对其管理 -
修改密码 -
查看博客列表:查看所有已发布的博客
-
博客详情页:查看博客内容及评论信息,可以对当前博客进行评论
-
关于
项目目录
数据库设计
数据库一共设计了三张表:用户表、博客表、评论表。
表之间的映射关系如下:
用户表和博客表一对多关系;用户和评论表一对多关系;博客表和评论表一对多关系。
其表的模型类代码如下:
class User(db.Model):
# 设置表名
__tablename__ = 'tb_user';
# id,主键并自动递增
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(64), unique=True)
password = db.Column(db.String(256), nullable=True)
name = db.Column(db.String(64))
# 设置只可写入,对密码进行加密
def password_hash(self, password):
self.password = generate_password_hash(password);
class Blog(db.Model):
__tablename__ = 'blog'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
title = db.Column(db.String(128))
text = db.Column(db.TEXT)
create_time = db.Column(db.String(64))
#关联用户id
user_id = db.Column(db.Integer, db.ForeignKey('tb_user.id'))
user = db.relationship('User', backref='user')
class Comment(db.Model):
__tablename__ = 'comment'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
text = db.Column(db.String(256)) # 评论内容
create_time = db.Column(db.String(64))
# 关联博客id
blog_id = db.Column(db.Integer, db.ForeignKey(blog.id))
# 关联用户id
user_id = db.Column(db.Integer, db.ForeignKey(tb_user.id))
blog = db.relationship(Blog, backref=blog)
user = db.relationship(User, backref=use)
功能实现
页面基本模板实现
页面使用的是Jinja2模板,Jinja2支持页面继承,所以导航栏重复性的页面代码,我们都可以写在一个文件中。这里我们先创建一个base.html文件,编写页面大致的框架。其他模块直接继承使用即可。
<!DOCTYPE html>
<html lang=en>
<head>
<meta charset=UTF-8>
<title>
{% block title %}
{# 其他页面可以重写标题 #}
{% endblock %}
</title>
<link rel=stylesheet href=/static/layui/css/layui.css>
<link rel=stylesheet href=/static/css/base.css>
<script src=/static/js/jquery.js></script>
<script src=/static/layui/layui.js></script>
{% block css %}
{% endblock %}
</head>
<body>
<div id=bg></div>
<ul class=layui-nav lay-filter=>
<li class=layui-nav-item><a href=/>在线博客平台</a></li>
{% if username %}
<li class=layui-nav-item{% block updatepwd_class %}{% endblock %}><a href=/updatePwd>修改密码</a></li>
{% endif %}
<li class=layui-nav-item{% block blog_class %}{% endblock %}><a href=/blog/blogAll>博客</a></li>
<li class=layui-nav-item{% block about_class %}{% endblock %}><a href=/about>关于</a></li>
{% if username %}
<li class=layui-nav-item style=float: right; margin-right: 30px;>
<a href=javascript:;>{{ name }}</a>
<dl class=layui-nav-child>
<dd><a href=/blog/myBlog>我的博客</a></dd>
<dd><a href=/blog/myComment>我的评论</a></dd>
<dd><a href=/logout>注销</a></dd>
</dl>
</li>
<li class=layui-nav-item{% block write_class %}{% endblock %} style=float: right><a href=/blog/writeBlog>写博客</a></li>
{% else %}
<li class=layui-nav-item{% block register_class %}{% endblock %} style=float: right><a href=/register>注册</a></li>
<li class=layui-nav-item{% block login_class %}{% endblock %} style=float: right><a href=/login>登录</a></li>
{% endif %}
</ul>
<div class=content>
{% block content %}
{# 其他页面内容 #}
{% endblock %}
</div>
<script>
layui.use('element', function(){
var element = layui.element;
});
</script>
</body>
</html>
这里页面使用了Layui定义了一个导航栏,展示了对应的功能模块。其中{% if username %},username为后台存放在session中的一个键值对,用于判断用户是否登录了,有些功能登录后才显示。
base.html模板文件完成后,我们在定义一个index.html来做项目的首页,直接继承base.html。这样首页index.html就节省了很多代码。如下:
{% extends 'base.html' %}
{% block title %}
在线博客平台
{% endblock %}
{% block content %}
<h1 style=margin: 35vh;>在线博客平台</h1>
{% endblock %}
首页效果如下:
登录与注册功能
登录
先定义一个登录的视图函数,可以接收GET、POST请求,GET请求为跳转到登录页面,POST请求为处理登录提交的请求,验证是否登录成功,登录成功后把当前登录对象的用户名存入session会话中。
# 登录请求
@index.route('/login', methods=['POST', 'GET'])
def login():
if request.method == 'GET':
return render_template('login.html')
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
user = User.query.filter(User.username == username).first();
# check_password_hash比较两个密码是否相同
if (user is not None) and (check_password_hash(user.password, password)):
session['username'] = user.username
session.permanent = True
return redirect(url_for('index.hello'))
else:
flash(账号或密码错误)
return render_template('login.html');
登录页面是用Layui写的一组form表单,也是基础的base.html,代码如下:
{% extends 'base.html' %}
{% block title %}
在线博客平台.登录
{% endblock %}
{% block css %}
<link rel=stylesheet href=/static/css/register.css>
{% endblock %}
{% block content %}
<div class=register>
<h1>登录</h1>
<p class=tip>
{% for item in get_flashed_messages() %}
{{ item }}
{% endfor %}
</p>
<form class=layui-form action=login method=post>
<div class=layui-form-item>
<label class=layui-form-label>用户名</label>
<div class=layui-input-block>
<input type=text name=username required lay-verify=required placeholder=请输入用户名 class=layui-input>
</div>
</div>
<div class=layui-form-item>
<label class=layui-form-label>密 码</label>
<div class=layui-input-block>
<input type=password name=password required lay-verify=required placeholder=请输入密码 class=layui-input>
</div>
</div>
<div class=layui-form-item>
<div class=layui-input-block>
<button class=layui-btn lay-submit lay-filter=formDemo>立即提交</button>
<button type=reset class=layui-btn layui-btn-primary>重置</button>
</div>
</div>
</form>
</div>
<script>
layui.use('form', function(){
var form = layui.form;
form.on('submit(formDemo)', function(data){
});
});
</script>
{% endblock %}
{% block login_class %}
layui-this
{% endblock %}
效果如下(账号和密码错误后,会有相应的提示信息):
注册和登录差不多,页面都是使用的同一个css样式文件,所以这里就贴代码出来了,需要的可以自行下载完整项目代码:GitHub地址。
修改密码
修改密码模块,因为数据库存放明文密码很不安全,所以这里使用了Werkzeug对密码进行了加密存储。对于WerkZeug密码加密想进一步了解的,可以访问Flask 使用Werkzeug实现密码加密。
因为数据库中存储的是加密后的密码,所以这里判断原密码是否正确需要使用check_password_hash函数进行判断。
定义一个修改密码的视图函数。
# 修改密码
@index.route(/updatePwd, methods=['POST', 'GET'])
@login_limit
def update():
if request.method == GET:
return render_template(updatePwd.html)
if request.method == 'POST':
lodPwd = request.form.get(lodPwd)
newPwd1 = request.form.get(newPwd1)
newPwd2 = request.form.get(newPwd2)
username = session.get(username);
user = User.query.filter(User.username == username).first();
if check_password_hash(user.password, lodPwd):
if newPwd1 != newPwd2:
flash(两次新密码不一致!)
return render_template(updatePwd.html)
else:
user.password_hash(newPwd2)
db.session.commit();
flash(修改成功!)
return render_template(updatePwd.html)
else:
flash(原密码错误!)
return render_template(updatePwd.html)
页面样式文件和登录注册引入的样式文件一致(原密码不正确或两次新密码不同,会给出相应的提示信息),代码如下:
{% extends 'base.html' %}
{% block title %}
在线博客平台.修改密码
{% endblock %}
{% block css %}
<link rel=stylesheet href=/static/css/register.css>
{% endblock %}
{% block content %}
<div class=register>
<h1>修改密码</h1>
<p class=tip>
{% for item in get_flashed_messages() %}
{{ item }}
{% endfor %}
</p>
<form class=layui-form action=updatePwd method=post>
<div class=layui-form-item>
<label class=layui-form-label>原密码</label>
<div class=layui-input-block>
<input type=password name=lodPwd required lay-verify=required placeholder=请输入原密码 class=layui-input>
</div>
</div>
<div class=layui-form-item>
<label class=layui-form-label>新密码</label>
<div class=layui-input-block>
<input type=password name=newPwd1 required lay-verify=required placeholder=请输入新密码 class=layui-input>
</div>
</div>
<div class=layui-form-item>
<label class=layui-form-label>确认新密码</label>
<div class=layui-input-block>
<input type=password name=newPwd2 required lay-verify=required placeholder=请再次输入新密码 class=layui-input>
</div>
</div>
<div class=layui-form-item>
<div class=layui-input-block>
<button class=layui-btn lay-submit lay-filter=formDemo>立即提交</button>
</div>
</div>
</form>
</div>
<script>
layui.use('form', function(){
var form = layui.form;
form.on('submit(formDemo)', function(data){
});
});
</script>
{% endblock %}
{% block updatepwd_class %}
layui-this
{% endblock %}
效果如下:
写博客
写博客,博客表中会保存标题、博客内容、当前时间等字段。如下是写博客的视图函数。
# 写博客页面
@blog.route('/writeBlog', methods=['POST', 'GET'])
@login_limit
def writeblog():
if request.method == 'GET':
return render_template('writeBlog.html')
if request.method == 'POST':
title = request.form.get(title)
text = request.form.get(text)
username = session.get('username')
# 获取当前系统时间
create_time = time.strftime(%Y-%m-%d %H:%M:%S)
user = User.query.filter(User.username == username).first()
blog = Blog(title=title, text=text, create_time=create_time, user_id=user.id)
db.session.add(blog)
db.session.commit();
blog = Blog.query.filter(Blog.create_time == create_time).first();
return render_template('blogSuccess.html', title=title, id=blog.id)
保存博客时会获取到当前系统时间,当做博客的发布时间。博客保存成功后,会返回保存成功页面,下面会有讲解。
写博客对应的html文件,代码如下。
{% extends 'base.html' %}
{% block title %}
在线博客平台.写博客
{% endblock %}
{% block css %}
<link rel=stylesheet type=text/css href=/static/editor/css/editormd.css/>
<script src=/static/editor/editormd.js type=text/javascript></script>
{% endblock %}
{% block content %}
<div class=main>
<form action=/blog/writeBlog class=layui-form method=post>
<div class=layui-form-item>
<label class=layui-form-label>标 题</label>
<div class=layui-input-block>
<input type=text name=title lay-verify=required placeholder=请输入标题 class=layui-input>
</div>
</div>
<div id=editormd>
<textarea name = text lay-verify=required style=display:none; ></textarea>
</div>
<div class=layui-form-item>
<div class=layui-input-block>
<button class=layui-btn style=width: 150px lay-submit lay-filter=formDemo>保存</button>
</div>
</div>
</form>
</div>
<script type=text/javascript>
layui.use('form', function(){
var form = layui.form;
form.on('submit(formDemo)', function(data){
});
});
$(function() {
editormd(editormd, {
width: 100%,
height: 600,
syncScrolling: single,
path: /static/editor/lib/, //依赖lib文件夹路径
emoji: true,
taskList: true,
tocm: true,
imageUpload: true, //开启本地图片上传
imageFormats: [jpg, jpeg, gif, png], //设置上传图片的格式
imageUploadURL: /blog/imgUpload //上传图片请求路径
});
});
</script>
{% endblock %}
{% block write_class %}
layui-this
{% endblock %}
写博客这里采用的是Markdown编辑器,对于Markdown编辑器之前写过一篇Markdown的使用方法,只不过后端用的是Java语言,感兴趣的小伙伴可以看看,Markdown的基本使用。Flask与之不同的是,后端接收Markdown上传图片时的语句不同,Flask接收Markdown上传图片的语句:
file = request.files.get('editormd-image-file');
其他的基本相同,毕竟Markdown是属于前端的知识,后端只要求根据规定个格式返回数据即可。
因为Markdown支持图片上传,那就必须的有文件上传的方法了。如下定义一个文件上传的视图函数(这里需要注意的是Markdown上传图片是使用的POST方法)。
# 上传图片
@blog.route('/imgUpload', methods=['POST'])
@login_limit
def imgUpload():
try:
file = request.files.get('editormd-image-file');
fname = secure_filename(file.filename);
ext = fname.rsplit('.')[-1];
# 生成一个uuid作为文件名
fileName = str(uuid.uuid4()) + . + ext;
filePath = os.path.join(static/uploadImg/, fileName);
file.save(filePath)
return {
'success': 1,
'message': '上传成功!',
'url': / + filePath
}
except Exception:
return {
'success': 0,
'message': '上传失败'
}
如果对上述的文件上传代码比较陌生,可以访问Flask 文件上传与下载,对Flask文件上传与下载进一步了解。
效果如下:
保存成功后,会返回保存成功页面,可以在写一篇,或者查看当前发布的文章。
查看博客列表
查看博客列表就是遍历所有已发布的博客。先定义一个视图函数,查询所有已发布的博客,传递到前端进行遍历显示。视图函数代码如下:
# 展示全部博客
@blog.route(/blogAll)
def blogAll():
# order_by按照时间倒序
blogList = Blog.query.order_by(Blog.create_time.desc()).all();
return render_template('blogAll.html', blogList=blogList)
因为最新发布的博客在数据库的最后一条,所以这里根据发布时间倒序查询。
页面代码如下:
{% extends 'base.html' %}
{% block title %}
在线博客平台.博客
{% endblock %}
{% block css %}
<link rel=stylesheet href=/static/css/blogAll.css>
{% endblock %}
{% block content %}
<div class=main>
<ul>
{% for blog in blogList %}
<li>
<a class=title href=/blog/showBlog/{{ blog.id }}>{{ blog.title }}</a>
<p>
发布人:{{ blog.user.name }} 发布时间:{{ blog.create_time }}
</p>
</li>
{% endfor %}
</ul>
</div>
{% endblock %}
{% block blog_class %}
layui-this
{% endblock %}
效果如下:
博客详情页面
在博客列表中点击博客的标题可以进入博客的详情页面,详情页面展示了博客的详细内容以及评论内容。
因为数据库中保存博客内容的是Markdown格式的,所以在这里需要解析成HTML格式,解析代码如下。
<script src=/static/editor/lib/marked.min.js></script>
<script src=/static/editor/lib/prettify.min.js></script>
<script src=/static/editor/lib/raphael.min.js></script>
<script src=/static/editor/lib/underscore.min.js></script>
<script src=/static/editor/lib/sequence-diagram.min.js></script>
<script src=/static/editor/lib/flowchart.min.js></script>
<script src=/static/editor/lib/jquery.flowchart.min.js></script>
<script src=/static/editor/editormd.js></script>
editormd.markdownToHTML(test, {
htmlDecode: style,script,iframe,
emoji: true,
taskList: true,
tex: true, // 默认不解析
flowChart: true, // 默认不解析
sequenceDiagram: true // 默认不解析
});
评论
在博客详情页面可以进行评论,评论使用的是Layui的编辑器,比较简约也可以达到想要的效果。
看上去是不是还可以,和页面也很搭。评论需要先登录才可以评论,如果没有登录则会提示登录。
如果登录评论后,会发送保存评论请求,携带当前博客的id和评论内容进行保存。
保存评论的视图函数。
# 评论
@blog.route(/comment, methods=['POST'])
@login_limit
def comment():
text = request.values.get('text')
blogId = request.values.get('blogId')
username = session.get('username')
# 获取当前系统时间
create_time = time.strftime(%Y-%m-%d %H:%M:%S)
user = User.query.filter(User.username == username).first()
comment = Comment(text=text, create_time=create_time, blog_id=blogId, user_id=user.id)
db.session.add(comment)
db.session.commit();
return {
'success': True,
'message': '评论成功!',
}
上述的博客内容解析与评论都在一个页面中,完整代码如下。
{% extends 'base.html' %}
{% block title %}
在线博客平台.博客
{% endblock %}
{% block css %}
<link rel=stylesheet type=text/css href=/static/editor/css/editormd.css/>
<link rel=stylesheet href=/static/css/showBlog.css>
<script src=/static/editor/lib/marked.min.js></script>
<script src=/static/editor/lib/prettify.min.js></script>
<script src=/static/editor/lib/raphael.min.js></script>
<script src=/static/editor/lib/underscore.min.js></script>
<script src=/static/editor/lib/sequence-diagram.min.js></script>
<script src=/static/editor/lib/flowchart.min.js></script>
<script src=/static/editor/lib/jquery.flowchart.min.js></script>
<script src=/static/editor/editormd.js></script>
{% endblock %}
{% block content %}
<div class=main>
<h1>{{ blog.title }}</h1>
<p>发布人:{{ blog.user.name }} 发布时间:{{ blog.create_time }}</p>
<hr>
<div id=test>
<textarea>{{ blog.text }}</textarea>
</div>
<fieldset class=layui-elem-field layui-field-title>
<legend>发表评论</legend>
<input type=hidden id=blog_id name=blogId value={{ blog.id }}>
<textarea id=lay_edit lay-verify=content name=text></textarea>
<button type=button class=layui-btn comSub>提交评论</button>
</fieldset>
<hr style=margin-top: 30px; margin-bottom: 20px;>
<ul class=comment>
{% for com in comment %}
<li>
<p class=myText>{{ com.text }}</p>
<p>评论人:{{ com.user.name }} 发布时间:{{ com.create_time }}</p>
</li>
{% endfor %}
</ul>
</div>
<script type=text/javascript>
$(function (){
$(.myText).each(function () {
$(this).html($(this).text());
});
})
editormd.markdownToHTML(test, {
htmlDecode: style,script,iframe,
emoji: true,
taskList: true,
tex: true, // 默认不解析
flowChart: true, // 默认不解析
sequenceDiagram: true // 默认不解析
});
layui.use(['layedit', 'form'], function () {
var form = layui.form;
var layedit = layui.layedit;
//创建一个编辑器
var index = layedit.build('lay_edit', {
height: 150,
tool: [
'face', //表情
'|', //分割线
'link' //超链接
]
});
$(.comSub).click(function (){
layui.use('layer', function(){
var layer = layui.layer;
{% if username %}
//获取评论内容
var text = layedit.getContent(index);
var blogId = $(#blog_id).val();
if(text == || text == undefined){
layer.msg(评论不能为空哦!, {icon: 0});
}else {
$.post(/blog/comment, {text: text, blogId: blogId}, function (result) {
if (result.success) {
window.location.href = '/blog/showBlog/' + blogId;
}
})
}
{% else %}
layer.confirm('登录后在评论哦!', {
btn: ['取消','登录']
}, function(index){
layer.close(index);
}, function(){
window.location.href = '/login';
});
{% endif %}
});
})
});
</script>
{% endblock %}
我的博客
登录之后在右上角导航栏可以查看我的博客,查看个人已经发布过的博客并进行管理。
定义一个视图函数,查询当前登录的用户发布的所有博客。
# 查看个人博客
@blog.route(/myBlog)
@login_limit
def myBlog():
username = session.get('username')
user = User.query.filter(User.username == username).first()
# order_by按照时间倒序
blogList = Blog.query.filter(Blog.user_id == user.id).order_by(Blog.create_time.desc()).all()
return render_template(myBlog.html, blogList=blogList)
页面与博客列表基本相似,但可以对其博客进行修改与删除。
修改博客
在我的博客中,有修改博客的链接,把当前的博客id当做参数传递到后台,查询当前这条博客的数据,进行修改。
# 博客修改
@blog.route(/update/<id>, methods=['POST', 'GET'])
@login_limit
def update(id):
if request.method == 'GET':
blog = Blog.query.filter(Blog.id == id).first();
return render_template('updateBlog.html', blog=blog)
if request.method == 'POST':
id = request.form.get(id)
title = request.form.get(title)
text = request.form.get(text)
blog = Blog.query.filter(Blog.id == id).first();
blog.title = title;
blog.text = text;
db.session.commit();
return render_template('blogSuccess.html', title=title, id=id)
修改页面和写博客的页面基本一样,在textarea标签中设置markdown编辑器的默认值。
<textarea name = text lay-verify=required style=display:none; >{{ blog.text }}</textarea>
删除博客
删除博客和修改一样,把博客的id传到后端,根据id删除数据库中对应的数据。
# 删除博客
@blog.route(/delete/<id>)
@login_limit
def delete(id):
blog = Blog.query.filter(Blog.id == id).first();
db.session.delete(blog);
db.session.commit();
return {
'state': True,
'msg': 删除成功!
}
删除成功后,使用JS删除页面上对应的DOM元素。
function del(url, that){
layui.use('layer', function(){
var layer = layui.layer;
layer.confirm('您确定要删除吗?', {
btn: ['取消','确定']
}, function(index){
layer.close(index);
}, function(){
$.get(url, function (data){
if(data.state){
$(that).parent().parent().parent().remove();
layer.msg(data.msg, {icon: 1});
}
})
});
});
}
我的评论
在页面的右上角不仅可以查看个人已发布的博客,也可以看到自己的所有评论信息。
根据评论列表,可以点击评论或博客,可以进入评论的博客详情页中;也可以对评论的内容进行删除操作。
定义一个视图函数,查询所有的评论内容,返回给前台遍历展示(同样根据时间倒序查询)。
# 用户所有的评论
@blog.route('/myComment')
@login_limit
def myComment():
username = session.get('username')
user = User.query.filter(User.username == username).first()
# order_by按照时间倒序
commentList = Comment.query.filter(Comment.user_id == user.id).order_by(Comment.create_time.desc()).all();
return render_template(myComment.html, commentList=commentList)
前端页面展示代码。
{% extends 'base.html' %}
{% block title %}
在线博客平台.我的评论
{% endblock %}
{% block css %}
<link rel=stylesheet href=/static/css/blogAll.css>
{% endblock %}
{% block content %}
<div class=main>
<ul>
{% for comment in commentList %}
<li>
<a class=title href=/blog/showBlog/{{ comment.blog_id }}>{{ comment.text }}</a>
<p>
博客:<a href=/blog/showBlog/{{ comment.blog_id }}>{{ comment.blog.title }}</a> 评论时间:{{ comment.create_time }}
<span class=operation>
<a href=javascript:; onclick=del('/blog/deleteCom/{{ comment.id }}', this)>删除</a>
</span>
</p>
</li>
{% endfor %}
</ul>
</div>
<script type=text/javascript>
$(function (){
$(.title).each(function () {
$(this).html($(this).text());
});
})
function del(url, that){
layui.use('layer', function(){
var layer = layui.layer;
layer.confirm('您确定要删除吗?', {
btn: ['取消','确定']
}, function(index){
layer.close(index);
}, function(){
$.get(url, function (data){
if(data.state){
$(that).parent().parent().parent().remove();
layer.msg(data.msg, {icon: 1});
}
})
});
});
}
</script>
{% endblock %}
页面样式和博客列表样式一致。
删除评论
在评论列表中有删除评论的链接,根据评论的id删除当前条评论,删除后,对应博客中的评论也随之删除。
# 删除评论
@blog.route('/deleteCom/<id>')
def deleteCom(id):
com = Comment.query.filter(Comment.id == id).first()
db.session.delete(com);
db.session.commit();
return {
'state': True,
'msg': 删除成功!
}
关于页面
关于页面可以简单的描述一下网站的设计及作用等,这里就没有写过多的内容了,可以自行设计。
注销
注销只需要清除session中的数据,返回首页即可。
# 退出
@index.route('/logout')
def logout():
session.clear()
return redirect(url_for('index.hello'))
定义错误页面
系统在平时使用中难免会遇到一些错误,但又不能直接让用户看到这些错误,所以我们可以定义一个错误页面,使其报错后都跳转到此页面。Flask中有两个视图函数处理404和500错误的,这里直接使用即可,这里两个视图函数都是跳转到了同一个页面(也可以跳转不同的页面)。
# 404页面
@app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404;
# 500页面
@app.errorhandler(500)
def internal_server_error(e):
return render_template('404.html'), 500;
错误页面这里就简单的插入了一张图片,添加了一个返回首页的链接。
<!DOCTYPE html>
<html lang=en>
<head>
<meta charset=UTF-8>
<title>网站走丢了。。。</title>
</head>
<style type=text/css>
body{
position: fixed;
width: 100%;
height: 100vh;
background: url('/static/img/404.gif') no-repeat;
background-size: cover;
z-index: -1;
}
a{
width: 65px;
display: inherit;
margin: 0 auto;
margin-top: 87vh;
padding: 5px 20px;
border: 1px solid;
border-radius: 8px;
}
</style>
<body>
<a href=/>返回首页</a>
</body>
</html>
效果如下:
源码下载
到这里整个博客系统就完成了,最后在附上下载链接:https://github.com/machaoyin/flask_blog/tree/master
版权声明:本文为CSDN博主「编程 小马」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:
https://blog.csdn.net/qq_40205116/article/details/110265729
纯免费在线学编程
扫码开始学
戳原文?在线学编程~
文章评论