赞
踩
基于Flask、Bootstrap4开发一个校园bbs论坛系列教程,该篇博客属于系列教程第二节,内容主要是对前端页面通用部分的实现。
在上一节中,我们介绍了整个项目的起因、功能设计等,这节开始,我们就是真正开始写(chao)代码了~~
在阅读这个系列教程之前,我们需要在我们的脑海中储备以下知识:
有了以上的基础知识,我们就可以很顺利的阅读这个系列的教程啦~
很多人都称我们程序员为码农码农,那我们就开始种地吧~
相信阅读过flask文档的朋友都知道flask包含有以下两种启动方式
- from flask import Flask
- app = Flask(__name__)
-
- @app.route('/')
- def index():
- return 'Hello, flask!'
-
-
- if __name__ == '__main__':
- app.run()
export FLASK_APP=app
然后通过flask run 命令来启动应用。
注意:Windows 用户请将export替换成set
在此教程中,我们采用第二种方式来进行应用启动,因为我们项目内容相对比较多,都是CURD:),应用的不同功能都分布在不同的模块中,使用flask的Blueprint来分割每个功能模块。
在bbs目录下新建__init__.py文件,该模块为我们的应用启动入口,在里面嵌入如下代码
- from flask import Flask
-
- def create_app():
- app = Flask('bbs')
-
- @app.route('/')
- def index():
- return 'Hello, university bbs'
- return app
然后在控制台中输入2.1节的命令,访问 http://127.0.0.1:5000,我们就可以看到如下页面了,说明我们的flask应用已经成功启动了。
上面的代码,我们创建了一个名为create_app 的函数,在该函数中我们实例化了一个Flask对象,然后通过装饰器的方式注册了一个路由'/',最后将这个Flask对象返回。当我们使用命令启动flask应用的时候,这个函数就是我们的入口函数,这种方式我们称作为工厂模式。
我们在开发过程中,肯定是修改代码之后就要立即调试,flask提供了debug模式,当我们开启debug的时候,我们修改完了代码,会auto reload 我们的应用,这样我们就不用每次修改了代码之后,手动去重新启动服务了,我们只需要在命令行中输入如下命令即可
export FLASK_ENV=development
我们的网站大概长成下面这个样子
其中,页眉和页脚在我们每个页面中都会出现,这样我们就可以将其抽取出来变为一个公共部分,又jinja2提供模板继承的功能,我们可以在其他页面中继承这些通用部分的内容。
在bbs/templates文件中我们新建一个frontend文件夹,然后新建一个名为base.html的文件,在该文件中嵌入以下内容:
bbs/templates/frontend/base.html
- <!DOCTYPE html>
- {% from "macro.html" import nav_item with context %}
- <!--suppress ALL -->
- <html lang="zh-hans">
- {% block head %}
- <head>
- <meta charset="UTF-8">
- <title>{% block title %}{% endblock %}-二狗学院</title>
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
- <link rel="shortcut icon" href="{{url_for('static', filename='img/favorite.png')}}" type="image/x-icon">
- <link rel="icon" href="{{ url_for('static', filename = 'img/favorite.png') }}" type="image/x-icon">
- <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.min.js"></script>
- <script src="https://cdn.staticfile.org/popper.js/1.15.0/umd/popper.min.js"></script>
- <link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
- <link rel="stylesheet" href="{{ url_for('static', filename='themes/darkly.bootstrap.min.css'}}">
- <script src="{{ url_for('static', filename='validator/form-validation.js') }}"></script>
- <script src="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
- </head>
- {% endblock %}
-
- {% block nav %}
- <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
- <div class="container align-self-end">
- <a class="navbar-brand" href="/"><i class="fa fa-bbs"></i>狗子学院</a>
- <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navHome" aria-controls="navHome" aria-expanded="false" aria-label="Toggle navigation">
- <span class="navbar-toggler-icon"></span>
- </button>
- <div class="collapse navbar-collapse" id="navHome">
- <ul class="navbar-nav mr-auto">
- <li class="nav-item dropdown mr-5">
- <a class="nav-link dropdown-toggle" href="#" id="talk" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-fire mr-1"></i>大食堂</a>
- <div class="dropdown-menu" aria-labelledby="talk">
- <a class="dropdown-item" href="#">杂谈</a>
- <a class="dropdown-item" href="#">趣事</a>
- <a class="dropdown-item" href="#">表白</a>
- </div>
- </li>
- <li class="nav-item dropdown mr-5">
- <a class="nav-link dropdown-toggle" href="#" id="talk" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-shopping-cart mr-1"></i>便利店</a>
- <div class="dropdown-menu" aria-labelledby="talk">
- <a class="dropdown-item" href="#">寻物</a>
- <a class="dropdown-item" href="#">咸鱼</a>
- <a class="dropdown-item" href="#">活动</a>
- </div>
- </li>
- <li class="nav-item dropdown mr-5">
- <a class="nav-link dropdown-toggle" href="#" id="talk" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-delicious mr-1"></i>组织</a>
- <div class="dropdown-menu" aria-labelledby="talk">
- <a class="dropdown-item" href="#">学院</a>
- <a class="dropdown-item" href="#">社团</a>
- <a class="dropdown-item" href="#">圈子</a>
- </div>
- </li>
- </ul>
- <form class="form-inline my-2 my-md-0">
- <input class="form-control" type="text" placeholder="请输入关键字" aria-label="Search" required>
- </form>
- </div>
- </div>
- </nav>
- {% endblock %}
- {% block content %}
- {% endblock %}
- {% block footer %}
- <footer class="container-fluid mt-4 py-0 bg-dark">
- <div class="card-body text-center px-0 f-14">
- <p class="card-text mb-1">Copyright © <span>2020</span>
- <a href="http://2dogz.cn/" target="_blank" title="官网">University BBS</a> Design by Flask1.01.
- </p>
- </div>
- </footer>
- {% endblock %}
- {% block script %}
- <script>
- $(function () {
- $('[data-toggle="tooltip"]').tooltip()
- })
- </script>
- {% endblock %}
- </html>

代码释义:
我们在base.html 文件中写了几个block
块定义,分别是head、nav、title、content、footer以及script。分别用来定义我们的html文件的引用、导航栏、标题、内容、页脚以及js代码块。通过{% block name %},当我们的子模板继承自base.html模板的时候,我们子模板可以重写这个block的定义,当然也可以使用{{ super() }}函数来继承父模板的定义,然后自己定义新的内容。
我们写完了页面的通用部分之后,就可以在主页中继承该模板了。在bbs/templates/frontend/文件夹中新建index.html文件,并嵌入下面的代码
bbs/templates/frontend/index.html
- {% extends "frontend/base.html" %}
- {% from "macro.html" import post_item, render_pagination with context%}
- {% block title %}
- 主页
- {% endblock %}
- {% block content %}
- <main>
- <div class="container mt-2">
-
- </div>
- </main>
- {% endblock %}
我使用extends关键字继承了基模板base.html,然后在content块中写了我们自己需要定义的内容。
在完成了我们主页模板代码之后,我们就需要通过路由将它渲染出来,并显示在用户的网页中。
在bbs目录下新建一个blueprint包,并新增模块index.py, 在其中嵌入如下代码
bbs/blueprint/index.py
- from flask import Blueprint, render_template
-
- index_bp = Blueprint('index_bp', __name__)
-
-
- @index_bp.route('/')
- @index_bp.route('/index/')
- def index():
- return render_template('frontend/index.html')
-
首先我们实例化了一个Blueprint对象,然后通过该对象注册了两个路由'/' 、'/index/',并将这两个路由指向视图函数index,在index函数中,我们将我们之前创建的主页文件渲染,然后返回给客户端。
我们在这里注册一个同样的路由,因此我们需要删除__init__.py模块中的index视图函数,同时我们在新建blueprint之后,需要将该蓝图进行注册,__init__.py最新代码如下
- from flask import Flask
- from bbs.blueprint.index import index_bp
-
-
- def create_app():
- app = Flask('bbs')
-
- register_bp(app)
- return app
-
-
- def register_bp(app: Flask):
- app.register_blueprint(index_bp)
此时,我们访问http://127.0.0.1:5000看到的将是如下页面
我们在访问网页的时候,经常会出现404,、500这种错误代码。如果我们使用flask提供的默认错误页面,是下面这种样子,如果用户不小心访问到了,将会一头雾水,不知所措,因此我们需要将特定错误页面进行处理,在用户进入错误页面之后,能对其有效的指引。
flask提供了errorhandle装饰器,能让我们很轻松的处理请求错误。在__init__.py模块中添加新的代码
bbs/__init__.py
- def create_app(config_name=None):.
- ...
- register_error_handlers(app)
-
-
-
- def register_error_handlers(app: Flask):
- @app.errorhandler(400)
- def bad_request(e):
- return render_template('error/400.html'), 400
-
- @app.errorhandler(403)
- def forbidden(e):
- return render_template('error/403.html'), 403
-
- @app.errorhandler(404)
- def not_found(e):
- return render_template('error/404.html'), 404
-
- @app.errorhandler(500)
- def server_error(e):
- return render_template('error/500.html'), 500

在register_error_handlers函数中,我们分别将对应的错误渲染了对应的错误模板了,因此当用户访问出错的时,页面显示的就是我们自己自定义的错误页面样式了。
在bbs/templates/error/目录中新建对应的模板文件,由于内容一致,这里只展示404页面的代码
bss/templates/error/404.html
- {% extends "frontend/base.html" %}
- {% block title %}
- 页面未找到
- {% endblock %}
- {% block content %}
- <main>
- <div class="container mt-2">
- <div class="card-body">
- <div class="card text-white bg-dark mb-3">
- <div class="card-body">
- <img src="{{ url_for('static', filename='img/404.png') }}" class="img-fluid d-block mx-auto">
- </div>
- <div class="card-footer text-right">
- <a class="btn btn-outline-danger" href="/">返回主页</a>
- </div>
- </div>
- </div>
- </div>
- </main>
- {% endblock %}

代码跟index.html类似,聪明的你应该看得懂,就不做多余的解释了。
然后我们输入一个未定义的路由,404页面就是下面你这个样子啦~~~
至此,本节的内容就已经全部做完啦~是不是很简单啊~
教程中的资源文件可以进入我的github仓库下载源代码使用 仓库连接
下一节,我们将开始进行用户注册登录功能的实现啦,尽请期待啦~~~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。