目录
前言:本项目基于vscode平台,使用flask搭建后端服务器,html,css,js编写前端用户登录以及问答发布页面,flask_sqlalchemy存储用户登录信息,flask_mail用于发送邮箱验证码进行用户注册,wtforms.validators进行登录注册等表单验证。最后实现用户注册,登录,发布问答,评论等功能,下面是一些具体部署和代码。
一、部署模块
这一部分主要介绍,该项目下有哪些文件,为什么需要这样部署文件,以及各个文件具体实现的功能。
文件结构如图:

1、blueprints蓝图目录
blueprints目录下存放模块化的路由文件,方便阅读以及后期维护,主要文件:
1)auth.py
存放用户登录注册的相关路由
2)qa.py
存放用户问答相关的路由
3)forms.py
验证表单,存放前两个文件中验证所需要的独立的类。验证的对象:
a.用户注册的用户名,邮箱等的格式是否符合类中规定的
b.用户注册验证码是否正确
2、migrations目录
用于存放数据库相关配置文件,刚修改models.py中的数据表单时,需要手动在终端执行
映射,映射三部曲如下:
1)flask db init 只需要在终端执行一次--生成一个文件夹,即migrations
2)flask db migrate 识别ORM模型,生成迁移脚本
3)flask db upgrade 运行迁移脚本,同步到数据库中
注:
每修改一次数据表的格式都需要手动执行后面两个代码
在数据库中会自动生成一个alembic_version库,用来记录迁移脚本版本号
3、static目录 -- 静态文件默认文件夹
用于存放css,js,图片等文件
4、templates目录 -- html文件默认文件夹
包括用户注册,登录,发布问答,发布评论的静态页面的书写。
5、 app.py文件
搭建服务器框架, 主执行文件
6、config.py文件 -- 配置文件
一般只需要写一次,配置文件,配置各种加密文件,服务器地址等等
1)mysql配置
2)email配置
7、decorators.py -- 装饰器文件
装饰器,验证用户是否登录,登陆了可以发布问答,反之跳转到登录页面
8、exts.py -- 第三方插件
放置一些可能会造成循环引用的代码,避免循环引用
9、models.py -- 数据表文件
创建数据库表单类,方便管理用户数据
总结:以上就是第一部分的模块部署,虽然前期部署花费了很长时间,但很显然,对于后期书写这很有必要,因为项目所需要的代码繁多,每一模块都有各自的作用,实现哪一方面的功能就去对应的目录文件下修改即可,会在无形中省下很多功夫。
二、代码实现
1、app.py
from flask import Flask, session, g # g 存储全部变量
from exts import db,mail
from models import UserModel # 导入模型
from blueprints.qa import bp as qes_bp # 导入蓝图对象
from blueprints.auth import bp as auth_bp
from flask_migrate import Migrate # 用于映射
import config
app = Flask(__name__)
app.debug = True
# 绑定配置文件
app.config.from_object(config)
# 绑定app
db.init_app(app)
mail.init_app(app)
# 映射关系
migrate = Migrate(app,db)
# 注册蓝图,绑定
app.register_blueprint(qes_bp)
app.register_blueprint(auth_bp)
@app.before_request # 钩子函数,在请求之前
def my_before():
user_id = session.get("user_id")
# 登录之后才有user_id
if user_id:
user = UserModel.query.get(user_id)
# 给g设置一个属性user,user上的值就是user
setattr(g,'user',user)
else: # 没有user_id,设置None,防止报错
setattr(g,'user',None)
# 上下文处理器,在所有模板当中都可访问其中的数据,user == g.user
@app.context_processor
def my_context_processor():
return {"user":g.user}
if __name__ == '__main__':
app.run('0.0.0.0',9527)
2、config.py -- 配置文件
mysql配置文件,需要修改,密码和自己建立的数据库名称
email配置文件,需要修改邮箱地址,邮箱授权密码,如何获取,往后看
SECRET_KEY = 'ndcinsidniveviniewos'
#encoding:utf8
USERNAME = 'root' # 账号
PASSWORD = '' # 密码,需要填写你自己的数据库密码
HOST = '127.0.0.1' # 服务器地址
PORT = '3306' # 默认端口号
DATABASE = '' # 使用的数据库,需要填写你自己的数据库名称
# 准备创建数据库连接实例,其中mysql和pymysql必须为小写形式
DB_URI = "mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8mb4".format(USERNAME,PASSWORD,HOST,PORT,DATABASE)
# 创建数据连接实例
SQLALCHEMY_DATABASE_URI = DB_URI
# 动态追踪必须设置,否则会报错,False或者True
SQLALCHEMY_TRACK_MODIFICATIONS = False
# 查询时会显示原始的SQL语句
# SQLALCHEMY_ECHO = True
# QQ邮箱配置密码
# 邮箱配置--开启了自己的邮箱
MAIL_SERVER = "smtp.qq.com"
MAIL_USE_SSL = True # 是否加密
MAIL_PORT = 465
MAIL_USERNAME = "" # 邮箱
MAIL_PASSWORD = "" # 邮箱密码
MAIL_DEFAULT_SENDER = "" # 同MAIL_USERNAME
如何获取邮箱密码,完成配置,使自己的邮箱可以作为邮箱服务器,完成这个项目:
1、打开qq邮箱,点击设置进入

2、切换到账户

3、开启下面的这个服务,获得的授权码就是password,我这里是已经开启了的

3、decorators.py -- 装饰器文件
from functools import wraps
from flask import g, redirect, url_for
# 装饰器,验证用户是否登录,登陆了可以发布问答,反之跳转到登录页面
def login_required(func):
# 保留func的信息,也就是传过来的public_question函数的信息,使得最后返回inner不会改变原函数
@wraps(func)
def inner(*args,**kwargs):
if g.user:
return func(*args,**kwargs)
else:
return redirect(url_for("auth.login"))
return inner
4、exts.py
from flask_sqlalchemy import SQLAlchemy
from flask_mail import Mail
db = SQLAlchemy()
mail = Mail()
5、models.py -- 数据库表单文件
from datetime import datetime
from exts import db
class UserModel(db.Model):
__tablename__ = "user"
id = db.Column(db.Integer,primary_key=True,autoincrement=True)
username = db.Column(db.String(100),nullable=False)
password = db.Column(db.String(200),nullable=False)
email = db.Column(db.String(100),nullable=False,unique=True)
# default制定了一个默认值,关联一个函数,获取当时创建的时间
join_time = db.Column(db.DateTime,default=datetime.now)
class EmailCaptchaModel(db.Model):
__tablename__ = "email_captcha"
id = db.Column(db.Integer,primary_key=True,autoincrement=True)
email = db.Column(db.String(100),nullable=False)
# default制定了一个默认值,关联一个函数,获取当时创建的时间
captcha = db.Column(db.String(100),nullable=False)
# 创建问题表单
class QuestionModel(db.Model):
__tablename__ = "question"
id = db.Column(db.Integer,primary_key=True,autoincrement=True)
title = db.Column(db.String(100),nullable=False)
content = db.Column(db.Text,nullable=True)
create_time = db.Column(db.DateTime,default=datetime.now)
# 外键
author_id = db.Column(db.Integer,db.ForeignKey("user.id"))
# 添加一个反向引用,back
author = db.relationship(UserModel,backref = "questions")
# 创建评论表单
class AnswerModel(db.Model):
__tablename__ = "answer"
id = db.Column(db.Integer,primary_key=True,autoincrement=True)
content = db.Column(db.Text,nullable=True)
create_time = db.Column(db.DateTime,default=datetime.now)
# 外键
question_id = db.Column(db.Integer,db.ForeignKey("question.id"))
author_id = db.Column(db.Integer,db.ForeignKey("user.id"))
# 关系,添加反向引用,并排序,新发的评论显示在上面
question = db.relationship(QuestionModel,backref=db.backref("answers",order_by=create_time.desc()))
author = db.relationship(UserModel,backref="answers")
三、templates静态文件
templates文件夹中配置html静态文件,使用base.html作为基础模板,将所有代码公用部分写在其中,其他的html文件使用block继承公用的,在编程自己特有的,这样代码看起来也更灵活清楚。这里作为示例,有如下base.html与register.html代码。
1、base.html -- 模板通用文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="{{ url_for('static',filename='bootstrap/bootstrap.4.6.min.css')}}">
<link rel="stylesheet" href="{{ url_for('static',filename='css/init.css')}}">
{% block head %}{% endblock %}
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="#">知了问答</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="/">首页 <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('qa.public_question') }}">发布问答</a>
</li>
<li class="nav-item ml-2">
<form class="form-inline my-2 my-lg-0" method="GET" action="{{ url_for('qa.search') }}">
<input class="form-control mr-sm-2" type="search" placeholder="关键字" aria-label="Search" name="q">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">搜索</button>
</form>
</li>
</ul>
<ul class="navbar-nav">
{% if user %}
<li class="nav-item">
<span class="nav-link">{{ user.username }}</span>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for("auth.logout") }}">退出登录</a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for("auth.login") }}">登录</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for("auth.register") }}">注册</a>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>
<div class="container">
{% block body %}{% endblock %}
</div>
</body>
</html>
2、register.html -- 注册目录
{% extends "base.html" %}
{% block title %}知了传课-注册{% endblock %}
{% block head %}
<script src="{{ url_for('static',filename='jquery/jquery.3.6.min.js')}}"></script>
<script src="{{ url_for('static',filename='js/register.js') }}"></script>
{% endblock %}
{% block body %}
<div class="row mt-4">
<div class="col"></div>
<div class="col">
<form method="POST">
<div class="form-group">
<label for="exampleInputEmail1">邮箱</label>
<input type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" name="email">
<small id="emailHelp" class="form-text text-muted">我们不会把邮箱用于其他用户</small>
</div>
<div class="form-group">
<label for="exampleInputEmail1">验证码</label>
<div class="input-group">
<input type="text" class="form-control" name="captcha">
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="button" id="captcha-btn">获取验证码</button>
</div>
</div>
</div>
<div class="form-group">
<label for="exampleInputEmail1">用户名</label>
<input type="text" class="form-control" name="username">
</div>
<div class="form-group">
<label for="exampleInputPassword1">密码</label>
<input type="password" class="form-control" id="exampleInputPassword1" name="password">
</div>
<div class="form-group">
<label for="exampleInputPassword1">确认密码</label>
<input type="password" class="form-control" name="password_confirm">
</div>
<button type="submit" class="btn btn-primary btn-block">立即注册</button>
</form>
</div>
<div class="col"></div>
</div>
{% endblock %}
四、成果展示

五、总结
作为新手项目,这个项目还有难度的,其中涉及到的知识点很多,要一一去了解很难。下面是整个项目的阿里云盘代码链接。因为还需要配置很多东西,即使有了完整代码也运行不了,还需要自己去修改配置文件config.py。还有更多问题,大家可以留言讨论。如果发现代码有什么问题,希望不吝指出,一起加油!
阿里云盘
MySQL02 https://www.aliyundrive.com/s/W1rNYemLqQo 提取码: 03vw 点击链接保存,或者复制本段内容,打开「阿里云盘」APP ,无需下载极速在线查看,视频原画倍速播放。

本文介绍了基于VSCode平台使用Flask构建的后端服务器项目,详细阐述了部署模块,包括blueprints蓝图、migrations目录、静态文件、模板、app.py、config.py等关键文件及其作用。代码实现部分涉及app.py、config.py、装饰器、数据库模型等,实现了用户注册、登录、问答发布等功能。同时,文章提到了使用Flask-SQLAlchemy存储用户信息、Flask-Mail发送邮箱验证码以及WTForms进行表单验证。最后展示了登录页面,并提供了项目成果的阿里云盘链接。

501

被折叠的 条评论
为什么被折叠?



