问答平台项目
1.项目的基础架构
把不同类型功能的代码, 放到不同的文件中,可以使项目架构更加的明确,下面是一种参考的方式
在项目文件夹下创建 config.py 用来存放 项目中的配置信息,创建 exts.py 放置一些扩展文件(例如一些第三方的模块,flask-sqlalchemy,等 创建 models.py 用来存放 sqlalchemy 中 ORM 中 数据表 对应的类。
在 app.py 中绑定config配置文件
模块之间的循环引用问题
蓝图(blueprint)
将所有的视图函数都写在 app.py 中,当项目 较大的时候不容易维护,
将不同类型的视图函数模块化,一类视图函数放在一个 py 文件中。
可以在项目文件夹下创建一个存放蓝图相关的python package, 在其中 创建 不同的 视图函数模块
在不同模块中定义不同的蓝图对象, 在 app.py 中 导入, 并注册
2.User 表模型创建
创建使用的数据库
在 config.py 中 添加 数据库相关的配置信息
在 models.py 中 创建 相关的 User模型类
在 app.py 中到导入 model.py 中 的 User 模型类(如果不在 app.py 中导入的话,使用 flask_migrate 进行数据库的映射时, 识别不到相关的模型)
使用 flask_migrate 进行 Python 类模型 和 数据表的映射
3.注册页面模版渲染
使用 写好的html 文件和 css 文件渲染注册 页面, 将 html 文件放到 templates 文件夹中, 将静态文件放入到static 文件夹中,在 auth 蓝图下 写 register 视图函数, 使用 render_template 指向 register.html, 渲染的页面
可能没有 css 样式和 相关的格式 ,需要将html 文件中加载 静态文件的方式 改成使用 url_for 的方式,
因为这里 加载 html 模块 使用的 jinjia2 , 要符合jinjia2 的语法。
模版文件中注册页面和 登录页面等的导航条和底部是一样的,可以写一个 父模版文件,使用模版继承来使模版文件更加简化
在 父模版中占位 用
4.Flask 发送邮件功能实现
注册功能的第一步,就是给用户输入的邮箱发送验证码,我们使用 flask-mail 发送验证码
想要发送邮件, 需要有一个邮箱服务器,可以自己搭建, 也可以使用第三方的邮件服务器, 例如 qq邮箱,网易邮箱,有各种企业邮箱, 这里用个人邮箱进行实验, 使用 flask_mail 发送邮件, 需要使用 SMTP协议(simple Mail Transfer Protocol)
首先登录 qq / 网易 等等邮箱,开启 SMTP 服务, QQ 邮箱在 邮箱设置 -> 账号->下,
网易邮箱在设置下, 开启 SMTP 服务后, 会有一个授权码, 邮箱配置中会用到
开启 邮箱 SMTP 服务以后, flask 可以通过 flask-mail 登录邮箱,发送邮件。
在 config.py 中添加 邮箱信息配置
在 exts.py 中创建 mail 对象, 在 app.py 中初始化
5.发送邮箱验证码功能实现
向邮箱发送验证码, 将邮箱的验证码存储在 数据库中, 在 models.py 中创建相应的 模型类
在 register.html 中 head block 占位的地方, 加载 js 文件, 通过 js 文件获取 register.html 页面 获取验证码的按钮, 给这个按钮绑定 向视图函数发送 获取验证码的事件
register.html 中 加载 绑定事件的 js 文件在 获取验证码按钮 的 html 内容的上方, html 文件是从上往下加载的
这导致 按钮还没有加载, 就要使用按钮的问题。
使用 jquery 的函数, jquery 的函数会在 整个网页的内容加载完成后, 再执行 函数
点击 register页面 获取验证码速度较慢和 如下视图函数中发送邮件的的 I/ o 操作有关
6.后端注册表单验证器实现
注册信息验证,使用表单验证来做数据验证 flask-wtf, wtforms
在 blueprints 目录下创建 forms.py, 使用wtforms 和 自定义验证进行验证
7.后端注册功能完成
完善register 视图函数, get 请求方式跳转到注册页面, post 请求方式, 提交数据, 首先使用表单验证器对
form 中的数据进行验证,数据验证成功后,将用户信息存储到user 数据库表中,
数据库用户密码不能存储明文,需要加密,可以使用 generate_password_hash
注册成功后,使用 redirect 重定向到 登录页面
注册失败,使用 redirect 重定向到 注册页面
重定向的时候,可以使用redircet(url_for(蓝图名.视图函数名))
8.登录页面模版渲染完成
login.html 使用 extends 和 block 继承 父模版
将登录页面独有的内容放入 body block 占位中。
9.登录功能后端实现
和 注册功能一样,区分请求方式, get 请求和post 请求返回不同的内容,get 请求返回登录页面,post 请求如果登录成功 跳转到首页,登录失败也重定向到 登录页面。在数据库中存储的是加密后的密码, 如果进行密码 对比?
加密 时 使用 generate_password_hash(password),
对比时, 可以使用 check_password_hash(数据库存储的加密值, password)
验证登录forms 中的内容, 在 forms.py 中写一个login 验证类
登录成功后, 如何保持登录状态, 需要使用到 cookie 和session
10.两个钩子函数
一般情况下,客户端向服务端发送请求,是直接访问 视图函数的,现在我们需要在访问视图函数前做一些事情
flask 中有一些钩子函数 :例如 before_request/ before_first_request/after_request/ 等等
hook
11.登录和非登录状态切换
导航条的显示是在 base.html 中做的,需要更改 base.html
修改如上图,红框内的html 代码逻辑
在 auth.py 中添加一个 logout 的视图函数,点击 退出登录的时候,执行 该视图函数
12.发布问答页面渲染
修改 public_question.html 为 Jinja2 的模版继承方式
13.发布问答后端功能实现
写一个视图函数来存储发布问答的内容,使用 wtforms 进行表单验证, 使用ORM 创建相关的数据表类,映射到数据库。
14.登录装饰器的实现
可以在 public 视图函数这里 判断,如果g.user 为空,重定向到auth.login页面
在一个页面可以这样写,但是如果 10 个页面都需要登录后,才能访问, 那就需要把判断 g.user 是否为空写 10 次,那么使用 装饰器就很方便了。
base.html 中
发布问答按钮点击时, 跳转到发布问答页面
15.首页问答列表渲染完成
继承 base.html , 填充 block 内容
首页视图函数指向 index.html, 从问答信息 数据表中倒序查询 所有的问答信息(问答信息过多的话, 需要分页)
在index.html 中 使用 jinja2 for 循环 展示每条问答信息
16.问答列表页渲染
继承base.html, 填充 block 内容
将 detail 中的详情信息改成 根据 question 不同,展示不同的信息
通过点击 index.html 中的 问答信息 title , 跳转到问答详情页
17.答案模型创建
在 models.py 中 创建问答 答案的数据库表 映射模型
18.发布答案功能完成
在 form.py 中定义 发布答案的表单验证类, 写一个视图函数来将发布的答案存储到数据库中
修改 问答 detail.html 中的 form 表单的 action, 即 表单的 提交 视图函数
通过 question.answers 反向引用, 获得一个问答问题的的所有评论答案, 并利用 jinja2 for 循环展示在detail.html 网页中 , 下图 42 行 answer.content 忘了 加 {{ }} 了, 正确应该是 {{ answer.content }}
19.搜索功能的实现
首先根据 前端传递的参数(即搜索内容), 写一个search视图函数, 将符合要求的问答从数据库中搜索出来,然后传递给 index.html 进行 循环展示
搜索 按钮是在 base.html 中的, 点击 搜索按钮,调用 search 视图函数,input 框的输入值,即为 q