创建一个flask项目目录(结构配置,SQLAlchemy,邮件,消息闪现等)
展示一下当前的目录结果
|-feng7309 # 项目文件夹
|--|apps # 统一管理所有的蓝图信息
|--|--|users # users 蓝图
|--|--|--|__init__.py # 蓝图声明和初始化
|--|--|--|login.py # 蓝图视图文件 执行业务逻辑
|--|--|--|for_db.py # 测试一些数据库的使用情况
|--|--|--|send_mail.py # 测试发送邮件
|--|utils # 工具文件夹,保存一些工具文件
|--|--|read_config.py # 读取配置文件的共计代码
|--|static # 保存静态文件
|--|--|css.py # 保存样式文件上
|--|--|js.py # 保存js文件
|--|--|images.py # 保存图片文件
|--|templates # 保存依稀静态的模板文件 html
|--|base_object.py # 用于创建一些扩展的对象,防止循环导入的现象
|--|config.ini # 外部信息配置文件
|--|create_app.py # 用于对flask项目进行数据初始化等信息配置,创建flask对象
|--|models.py # 所有的数据库模型代码
|--|req.txt # 需要的第三方包的名字和版本
|--|run.py # 程序入口文件
|--|setting.py # 做一些区分性的配置,分类拆分# 以下文件不用管
# enve 我自己的虚拟环境
# migration 迁移数据库生成的文件
1 创建空文件
# 创建一个空文件,将空文件突拖入pycharm中
# 创建 feng7309
2 创建环境创建目录结构
# 1 创建apps 文件夹,管理蓝图# 2 创建utils 保存工具文件# 3 创建虚拟环境 并将学你环境存放在项目目录下面 我用的是 python3.8并在虚拟环境终端安装flaskpip install flask
# 4 安装指定文件的包pip install -r req.txt
3 项目的编写
1 创建 入口文件 run.py
2 创建 create_app.py
3 创建 settings.py
4 在utils下创建 read_config.py 文件
5 创建 config.ini 文件
6 创建 base_object.py 统一创建第三方扩展对象
3.1 create_app.py
from flask import Flask
# 创建数据库对象
def create_app():flask_app = Flask(__name__)# 加载配置# 注册蓝图# 配置第三方扩展# 返回 flask对象return flask_app
3.2 run.py
from create_app import create_app
# 导入模型类
from models import Users
# 通过 create_app 创建flask对象
app = create_app()@app.route('/')
def index():return "Hello World!"
if __name__ == '__main__':app.run()
这样就可以运行了 ,127.0.0.1:5000 启动
3.3 配置信息,加载配置信息
config.ini
[DB]
HOST = 127.0.0.1
PORT = 3306
USERNAME = root
PASSWORD = root
NAME = flask_db
[SERVER]
DEBUG = True
HOST = 127.0.0.1
PORT = 5000
read_config.py
import configparserclass ReadConfig:"""创建一个读取配置文件的类"""def __init__(self):"""初始化连接配置对象,和配置文件位置"""self.config_path = r'C:\Users\FengHan7309\Desktop\base\feng7309\config.ini'self.read_config()def read_config(self):"""读取配置文件,返回读取配置对象:return: 读取文件配置文件对象"""self.config = configparser.ConfigParser()self.config.read(self.config_path)def config_value(self, section, key):"""通过获取secton和key获取指定的值:param section: section:param key: key:return: value"""value = self.config[section][key]return valuerc = ReadConfig()
settings.py
# -*- coding: utf-8 -*-
from utiles.read_config import rcclass BaseConfig:# 基础配置信息DEBUG = TrueSECRET_KEY = "qwertyuiopasdfghjklzxcvbnm"host = rc.config_value("DB", "HOST")port = int(rc.config_value("DB", "PORT"))username = rc.config_value("DB", "USERNAME")password = rc.config_value("DB", "PASSWORD")db_name = rc.config_value("DB", "NAME")SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{username}:{password}@{host}:{port}/{db_name}"SQLALCHEMY_TRACK_MODIFICATIONS = Falseclass DevelopmentConfig(BaseConfig):# 开发环境配置信息...class TestConfig(BaseConfig):# 测试环境配置信息...class ProductionConfig(BaseConfig):# 生产环境配置信息...
修改create_app.py 进行信息的的配置
# -*- coding: utf-8 -*-
"""
from flask import Flask
import settings
from flask_sqlalchemy import SQLAlchemydef create_app():flask_app = Flask(__name__)# 加载配置flask_app.config.from_object(settings.DevelopmentConfig)# 注册蓝图# 配置第三方扩展return flask_app
创建 base_object.py 创建扩展信息
from flask_mail import Mail
from flask_sqlalchemy import SQLAlchemy# 创建数据库对象
db = SQLAlchemy()
# 创建邮件对象
mails = Mail()
4 蓝图 users
创建一个python package,并在包下面创建一个login.py
4.1 _ _init _ _.py
from flask import Blueprintuser_dp = Blueprint('user', __name__)
# 引用蓝图的视图
from . import login
4.2 login.py
from apps.users import user_dp# 使用蓝图定义路由和视图,功能
@user_dp.route('/login', methods=['GET'])
def login():return "this is a login func"
4.3 修改create_app注册蓝图
from flask import Flaskimport settingsfrom apps.users import user_dp# 创建数据库对象def create_app():flask_app = Flask(__name__)# 加载配置flask_app.config.from_object(settings.DevelopmentConfig)# 注册蓝图flask_app.register_blueprint(user_dp, url_prefix="/user")# 配置第三方扩展return flask_app
重启项目,可以在127.0.0.1:5000/user/login 可以进行login信息的访问
5 SQLAlchemy的使用和配置
5.1 相关包的安装
使用mysql创建一个数据库名为 flask-db
pip install sqlalchemy
pip install lask_migrate
pip install flask_script
pip install pymysql
5.2 models.py
run文件夹同目录下创建models.py文件
from datetime import datetime
from email.policy import defaultfrom create_app import db# 创建用户表 命名为 f_users
class Users(db.Model):__tablename__ = 'f_users'id = db.Column(db.Integer, primary_key=True, autoincrement=True)username = db.Column(db.String(20))password = db.Column(db.String(20))age = db.Column(db.Integer)sex = db.Column(db.Integer)create_time = db.Column(db.DateTime, default=datetime.now)updated_time = db.Column(db.DateTime, default=datetime.now)
创建其他数据表的映射信息–用于测试
class User(db.Model):__tablename__ = 'users'id = db.Column(db.Integer, primary_key=True, autoincrement=True)username = db.Column(db.String(20))password = db.Column(db.String(20))# 一方指定关联的表 f 反向关联到user表articles = db.relationship('Article', backref='users')# 指定与Userinfo的关系 uselist 指定一对一的关系userinfo = relationship('UserInfo', backref='users', uselist=False)# 一个用户对应多个文章
class Article(db.Model):__tablename__ = 'articles'id = db.Column(db.Integer, primary_key=True, autoincrement=True)title = db.Column(db.String(20))content = db.Column(db.Text)# 指定外键是roles中的iduser_id = db.Column(db.Integer, ForeignKey('users.id'))# 一个用户对应一条信息
class UserInfo(db.Model):__tablename__ = 'userinfos'id = db.Column(db.Integer, primary_key=True, autoincrement=True)name = db.Column(db.String(20))age = db.Column(db.Integer)sex = db.Column(db.String(10))user_id = db.Column(db.Integer, ForeignKey('users.id'))# 定义多对对的关系 需要一个中间的对应关系
# 一篇文章有多个标签,同时一个标签也可以书与多个文章class Tag(db.Model):__tablename__ = 'tags'id = db.Column(db.Integer, primary_key=True, autoincrement=True)name = db.Column(db.String(20))# 定义对应关系
article_tag = db.Table('article_tag',db.Column('article_id', db.Integer, ForeignKey('articles.id')),db.Column('tag_id', db.Integer, ForeignKey('tags.id'))
)
5.3 修改create_app.py 进行第三方扩展
from flask import Flask
import settings
from flask_sqlalchemy import SQLAlchemy
from apps.users import user_dp# 导入创建的第三方扩展
from base_object import dbdef create_app():flask_app = Flask(__name__)# 加载配置flask_app.config.from_object(settings.DevelopmentConfig)# 注册蓝图flask_app.register_blueprint(user_dp, url_prefix="/user")# 配置第三方扩展db.init_app(app=flask_app)return flask_app
5.4 修改入口文件 run.py
from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager
from create_app import create_app, db
# 导入模型类
from models import Usersapp = create_app()# 初始化数据库执行
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)@app.route('/')
def index():return "Hello World!"if __name__ == '__main__':manager.run()
然后运行会出问题
5.5 出现问题解决
MigrateCommand 问题
降低一下migrate的版本
pip install flask_migrate==2.7.0
flask._cmpat 报错
点进去报错,修改 15行为
from flask_script._compat import text_type
manager启动出问题
usage: manage.py [-?] {db,shell,runserver} ...positional arguments:{db,shell,runserver}db Perform database migrationsshell Runs a Python shell inside Flask application context.runserver Runs the Flask development server i.e. app.run()optional arguments:-?, --help show this help message and exit
配置一下启动参数为 runserver 就可启动了
5.6 数据库迁移和初始化
数据初始化
执行命令
python run.py db init # 只需要执行一次
# 执行完成好会生成一个migration的文件夹不要改动,不用管它
数据表的迁移
python run.py db migrate
数据表的迁移
数据表执行
python run.py db upgrade
之后在数据库中就能够见到一个名为 f_user的表了
5.7 测试数据的CRUD 和SQLALchemy相关使用
SQLAlchemy的相关使用(不完全版本)
# 导入多条件查询的 or和and关键字
from sqlalchemy import or_, and_from apps.users import user_dp
from base_object import db
from models import User, UserInfo
# 重新封装一下 db.session
dbs = db.session# 通过访问接口测试数据库的使用
@user_dp.route('/add_data_users')
def add_data_users():"""添加1一条数据或多条数据:return:"""user = User(username="feng", password="123456")db.session.add(user)user = User(username="zhang", password="123456")db.session.add(user)db.session.commit()return 'add_data successfully'@user_dp.route('/add_data_users_all')
def add_data_users_all():"""一次添加多条数数据:return:"""user1 = User(username="liu", password="123456")user2 = User(username="zhao", password="123456")db.session.add_all([user1, user2])db.session.commit()return 'add_data successfully'@user_dp.route('/add_data_userinfo')
def add_data_userinfo():"""添加一个用户的信息:return:"""userinfo = UserInfo(name="张杰", age=20, sex='女', user_id=2)db.session.add(userinfo)db.session.commit()return 'add_data_userinfo successfully'@user_dp.route('/update_user_data')
def update_user_data():"""更新指定的数据:return:"""# step 1# user = User.query.get(2)# user.username = 'zhangjie'# user.password = '1111111'# db.session.commit()# db.session.close()# step 2db.session.query(User).filter(User.id == 1).update({'username': 'fenghan'})db.session.commit()db.session.close()return '更新数据成功'@user_dp.route('/delete_user_data')
def delete_user_data():"""删除数据:return:"""user = db.session.query(User).filter(User.id == 4).first()db.session.delete(user)db.session.commit()db.session.close()return '删除数据成功'@user_dp.route('/query_data')
def query_data():"""查询数据:return:"""# 1 查询完整及路all_user = db.session.query(User).all()# 2 查询具体的某条字段query_keyword = db.session.query(User.username).all()return 'query_data'@user_dp.route('/query_select_data')
def query_select_data():"""查询并筛选字段:return:"""# 1 filter方法res1 = dbs.query(User).filter(User.id == 1).all()# 2 filter_by方法筛选数据res2 = dbs.query(User).filter_by(id=2).all()return 'query_data'@user_dp.route('/query_many_option_data')
def query_many_option_data():"""查询并筛选字段:return:"""# 1 and_ 关系查询res1 = dbs.query(User).filter(User.username == 'fenghan', User.password == '123456').all()res_and = dbs.query(User).filter(and_(User.username == 'fenghan', User.password == '123456')).all()# 2 or_ 关系查询res2 = dbs.query(User).filter(or_(User.id == 1, User.username == 'liu')).all()return 'query_data'@user_dp.route('/query_link_data')
def query_link_data():"""查询字段信息 内连接,外连接:return:"""# 1 内连接 表1,表2都有数据res1 = dbs.query(User).join(UserInfo, User.id == UserInfo.user_id).all()# 2 外连接 表1有数据,表2不一定有数据res2 = dbs.query(User).outerjoin(UserInfo, User.id == UserInfo.user_id).all()return 'query_data'@user_dp.route('/do_sql')
def do_sql():"""直接执行sql语句:return:"""sql = 'select * from users'res = dbs.execute(sql)print(list(res))return 'query_data'@user_dp.route('/query_order_by')
def query_order_by():"""排序:return:"""# 降序res1 = dbs.query(User).order_by(User.id.desc()).all()res2 = dbs.query(User).order_by(-User.id).all()# 升序res3 = dbs.query(User).order_by(User.id).all()return 'query_data'
@user_dp.route('/query_limit_offset_by')
def query_limit_offset_by():"""排序:return:"""# limit 限制查询数据的条数# offset 过滤掉前多少条res1 =dbs.query(User).offset(1).limit(1).all()# 过滤一条,查询一条# 可以使用切片查找res2 = dbs.query(User).order_by(-User.id)[0:2]return 'query_data'
6 发送电子邮件信息
6.1 配置发送邮件的相关信息
这里不能通过from_object进行配置,为甚吗?-- 现在还不知道,采取以下方式进行配置
修改 create_app.py 文件,对有劲啊信息进行配置
from flask import Flask
import settingsfrom apps.users import user_dp
# 导入统一管理的 第三方扩展注册
from base_object import db, mailsdef create_app():# 配置静态文件 路径flask_app = Flask(__name__, template_folder='templates', static_folder='static', static_url_path='/static')# 加载配置flask_app.config.from_object(settings.DevelopmentConfig)# 对邮件的信息进行配置flask_app.config['MAIL_SERVER'] = 'smtp.qq.com'flask_app.config['MAIL_PORT'] = 465flask_app.config['MAIL_USERNAME'] = '2418028749@qq.com'flask_app.config['MAIL_PASSWORD'] = '你的密钥信息'flask_app.config['MAIL_USE_TLS'] = Falseflask_app.config['MAIL_USE_SSL'] = True# 注册蓝图 给访问加上前缀flask_app.register_blueprint(user_dp, url_prefix="/user")# 配置第三方扩展# 配置数据库db.init_app(app=flask_app)# 配置邮箱服务mails.init_app(app=flask_app)return flask_app
6.2 创建 send_mail.py 进行发送邮件操作
还是以接口的形式进行数据的测试
from flask_mail import Messagefrom apps.users import user_dp
from base_object import mails@user_dp.route('/send/')
def send_mail():# 创建一个信息对象msg = Message(# 标题subject="测试flask_mail发送邮件",# 发送人的邮箱地址sender='2418028749@qq.com',# 发送对象 可以有多个用户同时发送,列表形式传入recipients=['2418028749@qq.com'])# 邮件内容和主体msg.body = "this is a test message"msg.html = "<h1>This is a test message</h1>"# 携带附件# with open('../../static/images/001.jpeg') as f:# msg.attach('image.jpeg', 'image/jpeg', f.read())# 通过mails对象发送短信信息mails.send(msg)return "Send test message Success"
7 模板文件和消息闪现
7.1 模板文件
后端响应html模板文件 修改run.py
from flask import render_template, flash
from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager
from create_app import create_app, db
# 导入模型类
from models import *
app = create_app()
# 初始化数据库执行
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
# 路由输入一个数字进行响应模板 html 文件
@app.route('/<int:num>')
def index(num):if num > 0:# 消息闪现flash('You were successfully logged in','error')return render_template('index.html')# 渲染文件return render_template('index.html')if __name__ == '__main__':manager.run()
修改create_app.py文件,指定静态文件路径和模板文件夹
from flask import Flask
import settings
from apps.users import user_dp
from base_object import db, mails
def create_app():# 配置静态文件 路径flask_app = Flask(__name__, template_folder='templates', static_folder='static', static_url_path='/static')# template_folder='templates' 指定模板文件为templates# static_folder='static' 指定静态文件 static# static_url_path='/static' 指定静态文件路径 /static# 加载配置flask_app.config.from_object(settings.DevelopmentConfig)# 配置邮件数据对象flask_app.config['MAIL_SERVER'] = 'smtp.qq.com'flask_app.config['MAIL_PORT'] = 465flask_app.config['MAIL_USERNAME'] = '2418028749@qq.com'flask_app.config['MAIL_PASSWORD'] = 'znswdskbwnvyecdc'flask_app.config['MAIL_USE_TLS'] = Falseflask_app.config['MAIL_USE_SSL'] = True# 注册蓝图flask_app.register_blueprint(user_dp, url_prefix="/user")# 配置第三方扩展# 配置数据库db.init_app(app=flask_app)# 配置邮箱服务mails.init_app(app=flask_app)return flask_app
主模板文件 base.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><!-- 加载格式 {{ url_for('static',filename='文件路径') }}--><!--引入css文件--><link rel="stylesheet" href="{{ url_for('static',filename='/css/1.css') }}"><!--引入js文件--><script src="{{ url_for('static',filename='/js/1.js') }}"></script>
</head>
<body>
<h1>This is base page</h1>
<h1>主页返回的页面</h1>
<!--创建继承的模板块-->
{% block header %}
{% endblock %}
{# 获取稍息闪现的数据内容 #}
</body>
</html>
通过index.html 继承 base.html 文件
<!--指定继承的模板文件-->
{% extends 'base.html' %}
{# 模板继承 #}
{% block header %}
<h1>你是啊哈来看看就这个卡号就出现过咋看火箭股份</h1>
{% endblock %}
7.2 消息闪现
设置flash的消息闪现
修改run.py 文件
# 接口进行测试消息闪现
@app.route('/<int:num>')
def index(num):if num > 0:# 消息闪现 设置消息闪现内容# flash('闪现内容','消息级别')flash('You were successfully logged in','error')flash('1111111111111111 11111111111 11111111111')flash('222222222222 2222222222222222222222222222222')flash('You were successfully logged in','error')return render_template('index.html')# 渲染文件return render_template('index.html')
模板文件处理消息闪现的格式和方法
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><!--引入css文件--><link rel="stylesheet" href="{{ url_for('static',filename='/css/1.css') }}"><!--引入js文件--><script src="{{ url_for('static',filename='/js/1.js') }}"></script>
</head>
<body>
<h1>This is base page</h1>
<h1>主页返回的页面</h1>
{% block header %}
{% endblock %}
{# 获取稍息闪现的数据内容 #}
{% with messages = get_flashed_messages(with_categories=true) %}{# 如果有闪现的消息 执行下面语句 #}{% if messages %}<ul class=flashes>{#遍历所有的数据集,输出这个消息的内容#}{% for category,message in messages %}<li class="{{ category }}">{{ message }}</li>{% endfor %}</ul>{% endif %}
{% endwith %}
{#获取相对应错误信息#}
{#通过指定消息的类型,闪现指定的消息#}
{% with errors = get_flashed_messages(category_filter=["error"]) %}{% if errors %}<div class="alert-message block-message error"><a class="close" href="#">×</a><ul>{#只输出指定类型的消息#}{%- for msg in errors %}<li>{{ msg }}</li>{% endfor -%}</ul></div>{% endif %}
{% endwith %}
</body>
</html>
8 Flask-WTF扩展的使用
8.1 后端字段类型定义
在 run.py 下面定义一个类为RegisterFom的类
# 使用Flask—WTF编写表单信息
class RegisterForm(FlaskForm):"""自定义一个关于注册的方法"""username = StringField(label="用户名", validators=[DataRequired(message="用户名不能能为空!!")])password = PasswordField(label="密码", validators=[DataRequired("密码不能能为空!!"),Length(min=6, max=10, message="用户名长度在6-12位之间")])password2 = PasswordField(label="确认密码",validators=[DataRequired("密码不能能为空!!"), EqualTo("password", "两次密码不一致!")])age = IntegerField(label="年龄", validators=[DataRequired(message="年龄不能为空")])high = FloatField(label="身高单位厘米 可以为小数点", validators=[DataRequired(message="含恶搞不能为空")])submit = SubmitField(label="提交")# 自定义的函数来对指定 字段进行验证方法 # 格式 validate_要验证的字段名称def validate_username(self, field):# 验证逻辑if len(field.data) < 6:# 错误抛出的异常raise ValidationError("数据长度不能小于6位")def validate_age(self, field):if field.data < 0 or field.data > 120:raise ValidationError("请检查该字段是否有误!")
指定路由对该方法进行验证
@app.route('/test_wtf', methods=['GET', 'POST'])
def test_wtf():# 创建一个注册form表单对象form = RegisterForm()# 区分是那种请求方式if request.method == 'POST':# 验证表单的提交数据if form.validate_on_submit():# 获取表单中指定字段的数据内容username = form.username.datapassword = form.password.datapassword2 = form.password2.dataprint(username, password, password2)return "获取到了 WTF 表单中的信息"# get方法,渲染表单 将表单对象传回前端return render_template('test_wtf.html', form=form)
8.2 端模板定义
前端根据jinja2模板对表单格式进行渲染 test_wtf.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<h1>这里是一个验证 WTF 的HTML页面</h1>
{#定义一个form表单#}
<form action="" method="post">{#开启一个跨域表单验证#}{{ form.csrf_token }}{# 用户名 #}{# 根据表单对象指定lable标签 #}{{ form.username.label }}{# 根据表单对象指定username标签的输入内容 #}<p>{{ form.username }}</p>{# 根据表单对象指定校验的时候,不的错误提示 #}{% for msg in form.username.errors %}<p>{{ msg }}</p>{% endfor %}{# 密码 #}{{ form.password.label }}<p>{{ form.password }}</p>{% for msg in form.password.errors %}<p>{{ msg }}</p>{% endfor %}{# 确认密码 #}{{ form.password2.label }}<p>{{ form.password2 }}</p>{% for msg in form.password2.errors %}<p>{{ msg }}</p>{% endfor %}{# 年龄 #}{{ form.age.label }}<p>{{ form.age }}</p>{% for msg in form.age.errors %}<p>{{ msg }}</p>{% endfor %}{# 身高 #}{{ form.high.label }}<p>{{ form.high }}</p>{% for msg in form.high.errors %}<p>{{ msg }}</p>{% endfor %}{{ form.submit }}
</form>
</body>
</html>
9 flask-Bootstrap 扩展的使用
默认的使用前端的bootstrap框架的内容,格式等文件,默认需要继承与 bootstrap表
安装扩展包:pip install flask-bootstrap
修改base_object.py中创建
# 创建引入bootstrap对象
bs = Bootstrap()
在 create_app.py 中进行注册
# 配置bootstrapd数据
bs.init_app(app=flask_app)
后端路由访问
@app.route('/test_bootstrap', methods=['GET'])
def test_bootstrap():return render_template('test_bootstrap.html')
前端的继承和使用
{% extends "bootstrap/base.html" %}{% block title %}Flasky{% endblock %}{% block navbar %}
<div class="navbar navbar-inverse" role="navigation"><div class="container"><div class="navbar-header"><button type="button" class="navbar-toggle"data-toggle="collapse" data-target=".navbar-collapse"><span class="sr-only">Toggle navigation</span><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button><a class="navbar-brand" href="/">Flasky</a></div><div class="navbar-collapse collapse"><ul class="nav navbar-nav"><li><a href="/">Home</a></li></ul></div></div>
</div>
{% endblock %}{% block content %}
<div class="container"><div class="page-header"><h1>Hello, {{ name }}!</h1></div>
</div>
{% endblock %}