Flask实现个人博客系统(附源码)

冷不防 2022-12-24 12:56 631阅读 0赞

前面写了一些Flask相关的文章,这里使用Flask写了一个个人博客系统总结一下前面所学。项目全部代码也上传GitHub,地址:https://github.com/machaoyin/flask_blog/tree/master,如果对你有帮助,不妨动动你的小手指,帮忙star一下。

文章目录

    • 项目描述
    • 项目目录
    • 数据库设计
    • 功能实现
      • 页面基本模板实现
      • 登录与注册功能
      • 修改密码
      • 写博客
      • 查看博客列表
      • 博客详情页面
      • 评论
      • 我的博客
      • 修改博客
      • 删除博客
      • 我的评论
      • 删除评论
      • 关于页面
      • 注销
      • 定义错误页面
    • 源码下载

项目描述

开发环境:PyCharm、python3.7、MySQL5.5

使用技术:服务端是使用Flask开发的,前端是使用的Layui和Markdown编辑器所实现的。

项目包含功能如下:

  • 注册:注册账号
  • 登录:通过账号密码进行登录

    • 写博客:写博客采用的Markdown编辑器完成的。可以发布自己的博客
    • 我的博客:查看自己发布的博客并对其管理
    • 我的评论:查看自己的所有评论并对其管理
    • 修改密码
  • 查看博客列表:查看所有已发布的博客
  • 博客详情页:查看博客内容及评论信息,可以对当前博客进行评论
  • 关于

项目目录

在这里插入图片描述

数据库设计

数据库一共设计了三张表:用户表、博客表、评论表。
表之间的映射关系如下:
在这里插入图片描述
用户表和博客表一对多关系;用户和评论表一对多关系;博客表和评论表一对多关系。

其表的模型类代码如下:

  1. class User(db.Model):
  2. # 设置表名
  3. __tablename__ = 'tb_user';
  4. # id,主键并自动递增
  5. id = db.Column(db.Integer, primary_key=True, autoincrement=True)
  6. username = db.Column(db.String(64), unique=True)
  7. password = db.Column(db.String(256), nullable=True)
  8. name = db.Column(db.String(64))
  9. # 设置只可写入,对密码进行加密
  10. def password_hash(self, password):
  11. self.password = generate_password_hash(password);
  12. class Blog(db.Model):
  13. __tablename__ = 'blog'
  14. id = db.Column(db.Integer, primary_key=True, autoincrement=True)
  15. title = db.Column(db.String(128))
  16. text = db.Column(db.TEXT)
  17. create_time = db.Column(db.String(64))
  18. #关联用户id
  19. user_id = db.Column(db.Integer, db.ForeignKey('tb_user.id'))
  20. user = db.relationship('User', backref='user')
  21. class Comment(db.Model):
  22. __tablename__ = 'comment'
  23. id = db.Column(db.Integer, primary_key=True, autoincrement=True)
  24. text = db.Column(db.String(256)) # 评论内容
  25. create_time = db.Column(db.String(64))
  26. # 关联博客id
  27. blog_id = db.Column(db.Integer, db.ForeignKey("blog.id"))
  28. # 关联用户id
  29. user_id = db.Column(db.Integer, db.ForeignKey("tb_user.id"))
  30. blog = db.relationship("Blog", backref="blog")
  31. user = db.relationship("User", backref="use")

功能实现

页面基本模板实现

页面使用的是Jinja2模板,Jinja2支持页面继承,所以导航栏重复性的页面代码,我们都可以写在一个文件中。这里我们先创建一个base.html文件,编写页面大致的框架。其他模块直接继承使用即可。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>
  6. {% block title %}
  7. {# 其他页面可以重写标题 #}
  8. {% endblock %}
  9. </title>
  10. <link rel="stylesheet" href="/static/layui/css/layui.css">
  11. <link rel="stylesheet" href="/static/css/base.css">
  12. <script src="/static/js/jquery.js"></script>
  13. <script src="/static/layui/layui.js"></script>
  14. {% block css %}
  15. {% endblock %}
  16. </head>
  17. <body>
  18. <div id="bg"></div>
  19. <ul class="layui-nav" lay-filter="">
  20. <li class="layui-nav-item"><a href="/">在线博客平台</a></li>
  21. {% if username %}
  22. <li class="layui-nav-item{% block updatepwd_class %}{% endblock %}"><a href="/updatePwd">修改密码</a></li>
  23. {% endif %}
  24. <li class="layui-nav-item{% block blog_class %}{% endblock %}"><a href="/blog/blogAll">博客</a></li>
  25. <li class="layui-nav-item{% block about_class %}{% endblock %}"><a href="/about">关于</a></li>
  26. {% if username %}
  27. <li class="layui-nav-item" style="float: right; margin-right: 30px;">
  28. <a href="javascript:;">{
  29. { name }}</a>
  30. <dl class="layui-nav-child">
  31. <dd><a href="/blog/myBlog">我的博客</a></dd>
  32. <dd><a href="/blog/myComment">我的评论</a></dd>
  33. <dd><a href="/logout">注销</a></dd>
  34. </dl>
  35. </li>
  36. <li class="layui-nav-item{% block write_class %}{% endblock %}" style="float: right"><a href="/blog/writeBlog">写博客</a></li>
  37. {% else %}
  38. <li class="layui-nav-item{% block register_class %}{% endblock %}" style="float: right"><a href="/register">注册</a></li>
  39. <li class="layui-nav-item{% block login_class %}{% endblock %}" style="float: right"><a href="/login">登录</a></li>
  40. {% endif %}
  41. </ul>
  42. <div class="content">
  43. {% block content %}
  44. {# 其他页面内容 #}
  45. {% endblock %}
  46. </div>
  47. <script>
  48. layui.use('element', function(){
  49. var element = layui.element;
  50. });
  51. </script>
  52. </body>
  53. </html>

这里页面使用了Layui定义了一个导航栏,展示了对应的功能模块。其中{% if username %},username为后台存放在session中的一个键值对,用于判断用户是否登录了,有些功能登录后才显示。

base.html模板文件完成后,我们在定义一个index.html来做项目的首页,直接继承base.html。这样首页index.html就节省了很多代码。如下:

  1. {% extends 'base.html' %}
  2. {% block title %}
  3. 在线博客平台
  4. {% endblock %}
  5. {% block content %}
  6. <h1 style="margin: 35vh;">在线博客平台</h1>
  7. {% endblock %}

首页效果如下:
watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwMjA1MTE2_size_16_color_FFFFFF_t_70 2

登录与注册功能

登录

先定义一个登录的视图函数,可以接收GET、POST请求,GET请求为跳转到登录页面,POST请求为处理登录提交的请求,验证是否登录成功,登录成功后把当前登录对象的用户名存入session会话中。

  1. # 登录请求
  2. @index.route('/login', methods=['POST', 'GET'])
  3. def login():
  4. if request.method == 'GET':
  5. return render_template('login.html')
  6. if request.method == 'POST':
  7. username = request.form.get('username')
  8. password = request.form.get('password')
  9. user = User.query.filter(User.username == username).first();
  10. # check_password_hash比较两个密码是否相同
  11. if (user is not None) and (check_password_hash(user.password, password)):
  12. session['username'] = user.username
  13. session.permanent = True
  14. return redirect(url_for('index.hello'))
  15. else:
  16. flash("账号或密码错误")
  17. return render_template('login.html');

登录页面是用Layui写的一组form表单,也是基础的base.html,代码如下:

  1. {% extends 'base.html' %}
  2. {% block title %}
  3. 在线博客平台.登录
  4. {% endblock %}
  5. {% block css %}
  6. <link rel="stylesheet" href="/static/css/register.css">
  7. {% endblock %}
  8. {% block content %}
  9. <div class="register">
  10. <h1>登录</h1>
  11. <p class="tip">
  12. {% for item in get_flashed_messages() %}
  13. {
  14. { item }}
  15. {% endfor %}
  16. </p>
  17. <form class="layui-form" action="login" method="post">
  18. <div class="layui-form-item">
  19. <label class="layui-form-label">用户名</label>
  20. <div class="layui-input-block">
  21. <input type="text" name="username" required lay-verify="required" placeholder="请输入用户名" class="layui-input">
  22. </div>
  23. </div>
  24. <div class="layui-form-item">
  25. <label class="layui-form-label">密 码</label>
  26. <div class="layui-input-block">
  27. <input type="password" name="password" required lay-verify="required" placeholder="请输入密码" class="layui-input">
  28. </div>
  29. </div>
  30. <div class="layui-form-item">
  31. <div class="layui-input-block">
  32. <button class="layui-btn" lay-submit lay-filter="formDemo">立即提交</button>
  33. <button type="reset" class="layui-btn layui-btn-primary">重置</button>
  34. </div>
  35. </div>
  36. </form>
  37. </div>
  38. <script>
  39. layui.use('form', function(){
  40. var form = layui.form;
  41. form.on('submit(formDemo)', function(data){
  42. });
  43. });
  44. </script>
  45. {% endblock %}
  46. {% block login_class %}
  47. layui-this
  48. {% endblock %}

效果如下(账号和密码错误后,会有相应的提示信息):在这里插入图片描述
注册和登录差不多,页面都是使用的同一个css样式文件,所以这里就贴代码出来了,需要的可以自行下载完整项目代码:GitHub地址。

修改密码

修改密码模块,因为数据库存放明文密码很不安全,所以这里使用了Werkzeug对密码进行了加密存储。对于WerkZeug密码加密想进一步了解的,可以访问Flask 使用Werkzeug实现密码加密。

因为数据库中存储的是加密后的密码,所以这里判断原密码是否正确需要使用check_password_hash函数进行判断。

定义一个修改密码的视图函数。

  1. # 修改密码
  2. @index.route("/updatePwd", methods=['POST', 'GET'])
  3. @login_limit
  4. def update():
  5. if request.method == "GET":
  6. return render_template("updatePwd.html")
  7. if request.method == 'POST':
  8. lodPwd = request.form.get("lodPwd")
  9. newPwd1 = request.form.get("newPwd1")
  10. newPwd2 = request.form.get("newPwd2")
  11. username = session.get("username");
  12. user = User.query.filter(User.username == username).first();
  13. if check_password_hash(user.password, lodPwd):
  14. if newPwd1 != newPwd2:
  15. flash("两次新密码不一致!")
  16. return render_template("updatePwd.html")
  17. else:
  18. user.password_hash(newPwd2)
  19. db.session.commit();
  20. flash("修改成功!")
  21. return render_template("updatePwd.html")
  22. else:
  23. flash("原密码错误!")
  24. return render_template("updatePwd.html")

页面样式文件和登录注册引入的样式文件一致(原密码不正确或两次新密码不同,会给出相应的提示信息),代码如下:

  1. {% extends 'base.html' %}
  2. {% block title %}
  3. 在线博客平台.修改密码
  4. {% endblock %}
  5. {% block css %}
  6. <link rel="stylesheet" href="/static/css/register.css">
  7. {% endblock %}
  8. {% block content %}
  9. <div class="register">
  10. <h1>修改密码</h1>
  11. <p class="tip">
  12. {% for item in get_flashed_messages() %}
  13. {
  14. { item }}
  15. {% endfor %}
  16. </p>
  17. <form class="layui-form" action="updatePwd" method="post">
  18. <div class="layui-form-item">
  19. <label class="layui-form-label">原密码</label>
  20. <div class="layui-input-block">
  21. <input type="password" name="lodPwd" required lay-verify="required" placeholder="请输入原密码" class="layui-input">
  22. </div>
  23. </div>
  24. <div class="layui-form-item">
  25. <label class="layui-form-label">新密码</label>
  26. <div class="layui-input-block">
  27. <input type="password" name="newPwd1" required lay-verify="required" placeholder="请输入新密码" class="layui-input">
  28. </div>
  29. </div>
  30. <div class="layui-form-item">
  31. <label class="layui-form-label">确认新密码</label>
  32. <div class="layui-input-block">
  33. <input type="password" name="newPwd2" required lay-verify="required" placeholder="请再次输入新密码" class="layui-input">
  34. </div>
  35. </div>
  36. <div class="layui-form-item">
  37. <div class="layui-input-block">
  38. <button class="layui-btn" lay-submit lay-filter="formDemo">立即提交</button>
  39. </div>
  40. </div>
  41. </form>
  42. </div>
  43. <script>
  44. layui.use('form', function(){
  45. var form = layui.form;
  46. form.on('submit(formDemo)', function(data){
  47. });
  48. });
  49. </script>
  50. {% endblock %}
  51. {% block updatepwd_class %}
  52. layui-this
  53. {% endblock %}

效果如下:
在这里插入图片描述

写博客

写博客,博客表中会保存标题、博客内容、当前时间等字段。如下是写博客的视图函数。

  1. # 写博客页面
  2. @blog.route('/writeBlog', methods=['POST', 'GET'])
  3. @login_limit
  4. def writeblog():
  5. if request.method == 'GET':
  6. return render_template('writeBlog.html')
  7. if request.method == 'POST':
  8. title = request.form.get("title")
  9. text = request.form.get("text")
  10. username = session.get('username')
  11. # 获取当前系统时间
  12. create_time = time.strftime("%Y-%m-%d %H:%M:%S")
  13. user = User.query.filter(User.username == username).first()
  14. blog = Blog(title=title, text=text, create_time=create_time, user_id=user.id)
  15. db.session.add(blog)
  16. db.session.commit();
  17. blog = Blog.query.filter(Blog.create_time == create_time).first();
  18. return render_template('blogSuccess.html', title=title, id=blog.id)

保存博客时会获取到当前系统时间,当做博客的发布时间。博客保存成功后,会返回保存成功页面,下面会有讲解。

写博客对应的html文件,代码如下。

  1. {% extends 'base.html' %}
  2. {% block title %}
  3. 在线博客平台.写博客
  4. {% endblock %}
  5. {% block css %}
  6. <link rel="stylesheet" type="text/css" href="/static/editor/css/editormd.css"/>
  7. <script src="/static/editor/editormd.js" type="text/javascript"></script>
  8. {% endblock %}
  9. {% block content %}
  10. <div class="main">
  11. <form action="/blog/writeBlog" class="layui-form" method="post">
  12. <div class="layui-form-item">
  13. <label class="layui-form-label">标 题</label>
  14. <div class="layui-input-block">
  15. <input type="text" name="title" lay-verify="required" placeholder="请输入标题" class="layui-input">
  16. </div>
  17. </div>
  18. <div id="editormd">
  19. <textarea name = "text" lay-verify="required" style="display:none;" ></textarea>
  20. </div>
  21. <div class="layui-form-item">
  22. <div class="layui-input-block">
  23. <button class="layui-btn" style="width: 150px" lay-submit lay-filter="formDemo">保存</button>
  24. </div>
  25. </div>
  26. </form>
  27. </div>
  28. <script type="text/javascript">
  29. layui.use('form', function(){
  30. var form = layui.form;
  31. form.on('submit(formDemo)', function(data){
  32. });
  33. });
  34. $(function() {
  35. editormd("editormd", {
  36. width: "100%",
  37. height: 600,
  38. syncScrolling: "single",
  39. path: "/static/editor/lib/", //依赖lib文件夹路径
  40. emoji: true,
  41. taskList: true,
  42. tocm: true,
  43. imageUpload: true, //开启本地图片上传
  44. imageFormats: ["jpg", "jpeg", "gif", "png"], //设置上传图片的格式
  45. imageUploadURL: "/blog/imgUpload" //上传图片请求路径
  46. });
  47. });
  48. </script>
  49. {% endblock %}
  50. {% block write_class %}
  51. layui-this
  52. {% endblock %}

写博客这里采用的是Markdown编辑器,对于Markdown编辑器之前写过一篇Markdown的使用方法,只不过后端用的是Java语言,感兴趣的小伙伴可以看看,Markdown的基本使用。Flask与之不同的是,后端接收Markdown上传图片时的语句不同,Flask接收Markdown上传图片的语句:

  1. file = request.files.get('editormd-image-file');

其他的基本相同,毕竟Markdown是属于前端的知识,后端只要求根据规定个格式返回数据即可。

因为Markdown支持图片上传,那就必须的有文件上传的方法了。如下定义一个文件上传的视图函数(这里需要注意的是Markdown上传图片是使用的POST方法)。

  1. # 上传图片
  2. @blog.route('/imgUpload', methods=['POST'])
  3. @login_limit
  4. def imgUpload():
  5. try:
  6. file = request.files.get('editormd-image-file');
  7. fname = secure_filename(file.filename);
  8. ext = fname.rsplit('.')[-1];
  9. # 生成一个uuid作为文件名
  10. fileName = str(uuid.uuid4()) + "." + ext;
  11. filePath = os.path.join("static/uploadImg/", fileName);
  12. file.save(filePath)
  13. return {
  14. 'success': 1,
  15. 'message': '上传成功!',
  16. 'url': "/" + filePath
  17. }
  18. except Exception:
  19. return {
  20. 'success': 0,
  21. 'message': '上传失败'
  22. }

如果对上述的文件上传代码比较陌生,可以访问Flask 文件上传与下载,对Flask文件上传与下载进一步了解。

效果如下:
在这里插入图片描述
保存成功后,会返回保存成功页面,可以在写一篇,或者查看当前发布的文章。
在这里插入图片描述

查看博客列表

查看博客列表就是遍历所有已发布的博客。先定义一个视图函数,查询所有已发布的博客,传递到前端进行遍历显示。视图函数代码如下:

  1. # 展示全部博客
  2. @blog.route("/blogAll")
  3. def blogAll():
  4. # order_by按照时间倒序
  5. blogList = Blog.query.order_by(Blog.create_time.desc()).all();
  6. return render_template('blogAll.html', blogList=blogList)

因为最新发布的博客在数据库的最后一条,所以这里根据发布时间倒序查询。

页面代码如下:

  1. {% extends 'base.html' %}
  2. {% block title %}
  3. 在线博客平台.博客
  4. {% endblock %}
  5. {% block css %}
  6. <link rel="stylesheet" href="/static/css/blogAll.css">
  7. {% endblock %}
  8. {% block content %}
  9. <div class="main">
  10. <ul>
  11. {% for blog in blogList %}
  12. <li>
  13. <a class="title" href="/blog/showBlog/{
  14. { blog.id }}">{
  15. { blog.title }}</a>
  16. <p>
  17. 发布人:{
  18. { blog.user.name }} 发布时间:{
  19. { blog.create_time }}
  20. </p>
  21. </li>
  22. {% endfor %}
  23. </ul>
  24. </div>
  25. {% endblock %}
  26. {% block blog_class %}
  27. layui-this
  28. {% endblock %}

效果如下:
在这里插入图片描述

博客详情页面

在博客列表中点击博客的标题可以进入博客的详情页面,详情页面展示了博客的详细内容以及评论内容。

因为数据库中保存博客内容的是Markdown格式的,所以在这里需要解析成HTML格式,解析代码如下。

  1. <script src="/static/editor/lib/marked.min.js"></script>
  2. <script src="/static/editor/lib/prettify.min.js"></script>
  3. <script src="/static/editor/lib/raphael.min.js"></script>
  4. <script src="/static/editor/lib/underscore.min.js"></script>
  5. <script src="/static/editor/lib/sequence-diagram.min.js"></script>
  6. <script src="/static/editor/lib/flowchart.min.js"></script>
  7. <script src="/static/editor/lib/jquery.flowchart.min.js"></script>
  8. <script src="/static/editor/editormd.js"></script>
  9. editormd.markdownToHTML("test", {
  10. htmlDecode: "style,script,iframe",
  11. emoji: true,
  12. taskList: true,
  13. tex: true, // 默认不解析
  14. flowChart: true, // 默认不解析
  15. sequenceDiagram: true // 默认不解析
  16. });

评论

在博客详情页面可以进行评论,评论使用的是Layui的编辑器,比较简约也可以达到想要的效果。效果如图。
在这里插入图片描述
看上去是不是还可以,和页面也很搭。评论需要先登录才可以评论,如果没有登录则会提示登录。
在这里插入图片描述
如果登录评论后,会发送保存评论请求,携带当前博客的id和评论内容进行保存。
保存评论的视图函数

  1. # 评论
  2. @blog.route("/comment", methods=['POST'])
  3. @login_limit
  4. def comment():
  5. text = request.values.get('text')
  6. blogId = request.values.get('blogId')
  7. username = session.get('username')
  8. # 获取当前系统时间
  9. create_time = time.strftime("%Y-%m-%d %H:%M:%S")
  10. user = User.query.filter(User.username == username).first()
  11. comment = Comment(text=text, create_time=create_time, blog_id=blogId, user_id=user.id)
  12. db.session.add(comment)
  13. db.session.commit();
  14. return {
  15. 'success': True,
  16. 'message': '评论成功!',
  17. }

上述的博客内容解析与评论都在一个页面中,完整代码如下。

  1. {% extends 'base.html' %}
  2. {% block title %}
  3. 在线博客平台.博客
  4. {% endblock %}
  5. {% block css %}
  6. <link rel="stylesheet" type="text/css" href="/static/editor/css/editormd.css"/>
  7. <link rel="stylesheet" href="/static/css/showBlog.css">
  8. <script src="/static/editor/lib/marked.min.js"></script>
  9. <script src="/static/editor/lib/prettify.min.js"></script>
  10. <script src="/static/editor/lib/raphael.min.js"></script>
  11. <script src="/static/editor/lib/underscore.min.js"></script>
  12. <script src="/static/editor/lib/sequence-diagram.min.js"></script>
  13. <script src="/static/editor/lib/flowchart.min.js"></script>
  14. <script src="/static/editor/lib/jquery.flowchart.min.js"></script>
  15. <script src="/static/editor/editormd.js"></script>
  16. {% endblock %}
  17. {% block content %}
  18. <div class="main">
  19. <h1>{
  20. { blog.title }}</h1>
  21. <p>发布人:{
  22. { blog.user.name }} 发布时间:{
  23. { blog.create_time }}</p>
  24. <hr>
  25. <div id="test">
  26. <textarea>{
  27. { blog.text }}</textarea>
  28. </div>
  29. <fieldset class="layui-elem-field layui-field-title">
  30. <legend>发表评论</legend>
  31. <input type="hidden" id="blog_id" name="blogId" value="{
  32. { blog.id }}">
  33. <textarea id="lay_edit" lay-verify="content" name="text"></textarea>
  34. <button type="button" class="layui-btn comSub">提交评论</button>
  35. </fieldset>
  36. <hr style="margin-top: 30px; margin-bottom: 20px;">
  37. <ul class="comment">
  38. {% for com in comment %}
  39. <li>
  40. <p class="myText">{
  41. { com.text }}</p>
  42. <p>评论人:{
  43. { com.user.name }} 发布时间:{
  44. { com.create_time }}</p>
  45. </li>
  46. {% endfor %}
  47. </ul>
  48. </div>
  49. <script type="text/javascript">
  50. $(function (){
  51. $(".myText").each(function () {
  52. $(this).html($(this).text());
  53. });
  54. })
  55. editormd.markdownToHTML("test", {
  56. htmlDecode: "style,script,iframe",
  57. emoji: true,
  58. taskList: true,
  59. tex: true, // 默认不解析
  60. flowChart: true, // 默认不解析
  61. sequenceDiagram: true // 默认不解析
  62. });
  63. layui.use(['layedit', 'form'], function () {
  64. var form = layui.form;
  65. var layedit = layui.layedit;
  66. //创建一个编辑器
  67. var index = layedit.build('lay_edit', {
  68. height: 150,
  69. tool: [
  70. 'face', //表情
  71. '|', //分割线
  72. 'link' //超链接
  73. ]
  74. });
  75. $(".comSub").click(function (){
  76. layui.use('layer', function(){
  77. var layer = layui.layer;
  78. {% if username %}
  79. //获取评论内容
  80. var text = layedit.getContent(index);
  81. var blogId = $("#blog_id").val();
  82. if(text == "" || text == undefined){
  83. layer.msg("评论不能为空哦!", {icon: 0});
  84. }else {
  85. $.post("/blog/comment", {text: text, blogId: blogId}, function (result) {
  86. if (result.success) {
  87. window.location.href = '/blog/showBlog/' + blogId;
  88. }
  89. })
  90. }
  91. {% else %}
  92. layer.confirm('登录后在评论哦!', {
  93. btn: ['取消','登录']
  94. }, function(index){
  95. layer.close(index);
  96. }, function(){
  97. window.location.href = '/login';
  98. });
  99. {% endif %}
  100. });
  101. })
  102. });
  103. </script>
  104. {% endblock %}

我的博客

登录之后在右上角导航栏可以查看我的博客,查看个人已经发布过的博客并进行管理。
在这里插入图片描述
定义一个视图函数,查询当前登录的用户发布的所有博客。

  1. # 查看个人博客
  2. @blog.route("/myBlog")
  3. @login_limit
  4. def myBlog():
  5. username = session.get('username')
  6. user = User.query.filter(User.username == username).first()
  7. # order_by按照时间倒序
  8. blogList = Blog.query.filter(Blog.user_id == user.id).order_by(Blog.create_time.desc()).all()
  9. return render_template("myBlog.html", blogList=blogList)

页面与博客列表基本相似,但可以对其博客进行修改与删除。
在这里插入图片描述

修改博客

在我的博客中,有修改博客的链接,把当前的博客id当做参数传递到后台,查询当前这条博客的数据,进行修改。

  1. # 博客修改
  2. @blog.route("/update/<id>", methods=['POST', 'GET'])
  3. @login_limit
  4. def update(id):
  5. if request.method == 'GET':
  6. blog = Blog.query.filter(Blog.id == id).first();
  7. return render_template('updateBlog.html', blog=blog)
  8. if request.method == 'POST':
  9. id = request.form.get("id")
  10. title = request.form.get("title")
  11. text = request.form.get("text")
  12. blog = Blog.query.filter(Blog.id == id).first();
  13. blog.title = title;
  14. blog.text = text;
  15. db.session.commit();
  16. return render_template('blogSuccess.html', title=title, id=id)

修改页面和写博客的页面基本一样,在textarea标签中设置markdown编辑器的默认值。

  1. <textarea name = "text" lay-verify="required" style="display:none;" >{
  2. { blog.text }}</textarea>

删除博客

删除博客和修改一样,把博客的id传到后端,根据id删除数据库中对应的数据。

  1. # 删除博客
  2. @blog.route("/delete/<id>")
  3. @login_limit
  4. def delete(id):
  5. blog = Blog.query.filter(Blog.id == id).first();
  6. db.session.delete(blog);
  7. db.session.commit();
  8. return {
  9. 'state': True,
  10. 'msg': "删除成功!"
  11. }

删除成功后,使用JS删除页面上对应的DOM元素。

  1. function del(url, that){
  2. layui.use('layer', function(){
  3. var layer = layui.layer;
  4. layer.confirm('您确定要删除吗?', {
  5. btn: ['取消','确定']
  6. }, function(index){
  7. layer.close(index);
  8. }, function(){
  9. $.get(url, function (data){
  10. if(data.state){
  11. $(that).parent().parent().parent().remove();
  12. layer.msg(data.msg, {icon: 1});
  13. }
  14. })
  15. });
  16. });
  17. }

我的评论

在页面的右上角不仅可以查看个人已发布的博客,也可以看到自己的所有评论信息。
在这里插入图片描述
根据评论列表,可以点击评论或博客,可以进入评论的博客详情页中;也可以对评论的内容进行删除操作。
定义一个视图函数,查询所有的评论内容,返回给前台遍历展示(同样根据时间倒序查询)。

  1. # 用户所有的评论
  2. @blog.route('/myComment')
  3. @login_limit
  4. def myComment():
  5. username = session.get('username')
  6. user = User.query.filter(User.username == username).first()
  7. # order_by按照时间倒序
  8. commentList = Comment.query.filter(Comment.user_id == user.id).order_by(Comment.create_time.desc()).all();
  9. return render_template("myComment.html", commentList=commentList)

前端页面展示代码。

  1. {% extends 'base.html' %}
  2. {% block title %}
  3. 在线博客平台.我的评论
  4. {% endblock %}
  5. {% block css %}
  6. <link rel="stylesheet" href="/static/css/blogAll.css">
  7. {% endblock %}
  8. {% block content %}
  9. <div class="main">
  10. <ul>
  11. {% for comment in commentList %}
  12. <li>
  13. <a class="title" href="/blog/showBlog/{
  14. { comment.blog_id }}">{
  15. { comment.text }}</a>
  16. <p>
  17. 博客:<a href="/blog/showBlog/{
  18. { comment.blog_id }}">{
  19. { comment.blog.title }}</a> 评论时间:{
  20. { comment.create_time }}
  21. <span class="operation">
  22. <a href="javascript:;" onclick="del('/blog/deleteCom/{
  23. { comment.id }}', this)">删除</a>
  24. </span>
  25. </p>
  26. </li>
  27. {% endfor %}
  28. </ul>
  29. </div>
  30. <script type="text/javascript">
  31. $(function (){
  32. $(".title").each(function () {
  33. $(this).html($(this).text());
  34. });
  35. })
  36. function del(url, that){
  37. layui.use('layer', function(){
  38. var layer = layui.layer;
  39. layer.confirm('您确定要删除吗?', {
  40. btn: ['取消','确定']
  41. }, function(index){
  42. layer.close(index);
  43. }, function(){
  44. $.get(url, function (data){
  45. if(data.state){
  46. $(that).parent().parent().parent().remove();
  47. layer.msg(data.msg, {icon: 1});
  48. }
  49. })
  50. });
  51. });
  52. }
  53. </script>
  54. {% endblock %}

页面样式和博客列表样式一致。

删除评论

在评论列表中有删除评论的链接,根据评论的id删除当前条评论,删除后,对应博客中的评论也随之删除。

  1. # 删除评论
  2. @blog.route('/deleteCom/<id>')
  3. def deleteCom(id):
  4. com = Comment.query.filter(Comment.id == id).first()
  5. db.session.delete(com);
  6. db.session.commit();
  7. return {
  8. 'state': True,
  9. 'msg': "删除成功!"
  10. }

关于页面

关于页面可以简单的描述一下网站的设计及作用等,这里就没有写过多的内容了,可以自行设计。
在这里插入图片描述

注销

注销只需要清除session中的数据,返回首页即可。

  1. # 退出
  2. @index.route('/logout')
  3. def logout():
  4. session.clear()
  5. return redirect(url_for('index.hello'))

定义错误页面

系统在平时使用中难免会遇到一些错误,但又不能直接让用户看到这些错误,所以我们可以定义一个错误页面,使其报错后都跳转到此页面。Flask中有两个视图函数处理404和500错误的,这里直接使用即可,这里两个视图函数都是跳转到了同一个页面(也可以跳转不同的页面)。

  1. # 404页面
  2. @app.errorhandler(404)
  3. def page_not_found(e):
  4. return render_template('404.html'), 404;
  5. # 500页面
  6. @app.errorhandler(500)
  7. def internal_server_error(e):
  8. return render_template('404.html'), 500;

错误页面这里就简单的插入了一张图片,添加了一个返回首页的链接。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>网站走丢了。。。</title>
  6. </head>
  7. <style type="text/css">
  8. body{
  9. position: fixed;
  10. width: 100%;
  11. height: 100vh;
  12. background: url('/static/img/404.gif') no-repeat;
  13. background-size: cover;
  14. z-index: -1;
  15. }
  16. a{
  17. width: 65px;
  18. display: inherit;
  19. margin: 0 auto;
  20. margin-top: 87vh;
  21. padding: 5px 20px;
  22. border: 1px solid;
  23. border-radius: 8px;
  24. }
  25. </style>
  26. <body>
  27. <a href="/">返回首页</a>
  28. </body>
  29. </html>

效果如下
在这里插入图片描述

源码下载

到这里整个博客系统就完成了,最后在附上下载链接:https://github.com/machaoyin/flask_blog/tree/master。如果对你有帮助,不妨动动你的小手指,帮忙star一下。

创作不易,如果感觉对你有帮助,可以点赞、关注支持一下博主!

发表评论

表情:
评论列表 (有 0 条评论,631人围观)

还没有评论,来说两句吧...

相关阅读

    相关 个人系统

    个人博客系统 摘 要 个人博客系统采用B/S结构、java开发语言、以及Mysql数据库等技术。系统主要分为管理员和博客两部分,管理员主要功能包括:个人中心、文章分类管理、