Flask 搭建网站记录
建站目的
主要目的是用于维护资料的方便性。可以加一些验证减少人员的错误。
- 自动生成新的id,而不是靠人去自己找,杜绝重复
- 资料放在db,不会存在太多版本,资料是一致的
- 有上传和下载excel的功能,方便批量生成ID
- 有query功能,可以针对特定的资料进行编辑
文件目录
-app
- templates
- login.html
- index.html
- base.html
- upload.html
- query.html
- run.py
- query.py
- upload.py
- db.py
- auth.py
使用的功能
Blueprint
由于有好几个功能,最初的设计是全部放到一个主文件里面去。但是由于后面功能的增加,感觉不是太便捷。所以修改为使用蓝图进行配置。
import upload
import auth
import query
app.register_blueprint(upload.bp)
app.register_blueprint(auth.bp)
app.register_blueprint(query.bp)
auth.py 配置
bp = Blueprint('auth', __name__)
配置的时候比较简单,需要注意的是使用的时候要修改一些URL的引用。比如我auth.py
里面有个login
方法。如果未登录时,都要跳转回这里,需要使用redirect(url_for('auth.login'))
。
在每个文件里面可以是用同样的变量名bp
,这样比较方便在主函数的调用注册。
db的使用
最初用的Pymysql 可以做SQL的简单增删改查。但是处理文件时,我使用了pandas库,而pandas默认只能支持sqlalchemy。所以在切分文件时,改成了全部使用sqlalchemy.
DB的初始化是参考官网的一个sample去初始化的。这里的调试遇到的最大问题。就是如果在主函数初始化,在其他文件去调用DB时,会报循环引用错误。就是app.py import upload.py, 而upload.py又引用的app.py里面的一个函数或者变量。最终导致一直报错。这种情形如果都写一个文件里面,不会出现。
解决方式是,在主函数里面,初始化DB db.init_db(app)
。原始范例里面init_db_command 是一个命令行命令,当它被执行时,Flask 会自动创建并推送应用上下文,因此在这个命令中调用 init_db 不会有上下文问题。而如果要直接使用init_db函数只是注册了命令,实际的数据库初始化是在命令行调用时执行的。
from flask import g
from sqlalchemy import create_engine
def get_db():
"""Connect to the application's configured database. The connection
is unique for each request and will be reused if this is called
again.
"""
if "db" not in g:
g.db = create_engine("mysql+pymysql://root:mysql@localhost/powerbi")
return g.db
def close_db(e=None):
"""If this request connected to the database, close the
connection.
"""
db = g.pop("db", None)
if db is not None:
db.close()
def init_db(app):
"""Clear existing data and create new tables."""
with app.app_context()
db = get_db()
# with current_app.open_resource("schema.sql") as f:
# db.executescript(f.read().decode("utf8"))
当我们在其他文件需要引用数据库时,直接import这个db文件的get_db方法即可。返回的是一个SQLAlchemy的engine
from db import get_db
db=get_db()
其他文件的逻辑实现
这里实现就比较简单的,大多是数据的增删改查。附上几个简单的用法。
搭配pandas使用
# 使用pandas查询资料获取结果 query = "SELECT * FROM dpn_status WHERE Substitute = %(substitute_id)s" params = {'substitute_id': id} results = pd.read_sql_query(query, con=db_engine, params=params) print(results)
- 直接执行sql,需要注意SQL语句要搭配text()函数,不然无法执行
with db.connect() as conn:
query = text(
'''SELECT * FROM dpn_status WHERE Substitute = :sub LIMIT 1'''
)
result = conn.execute(query, {
'sub': substitutes[0]
}).fetchone()
print(result)
conn.execute(
text(
'''INSERT INTO dpn_status (DPN, 71PN,Substitute,Model,Region,Series,MP,EOP,EOW,WarrantyPeriod) VALUES (:DPN,:71PN,:Substitute,:Model,:Region,:Series,:MP,:EOP,:EOW,:WarrantyPeriod)'''
), {
"DPN": dpns[i],
"71PN": pn71s[i],
"Substitute": substitutes[i],
"Model": result[4],
"Region": regions[i],
"Series": result[6],
"MP": result[7],
"EOP": result[8],
"EOW": result[9],
"WarrantyPeriod": result[10]
})
conn.commit()
- 删除资料,参数的搭配使用
query = text("DELETE FROM dpn_status where id = :id")
result = db_engine.connect().execute(query, {'id': id})
不足和思考
整体实现这个功能大约用了两周的时间。对于框架的使用还是不够熟悉,特别是数据库的初始化部分。现在回想一下,整个思路清晰多了。当然这里还有一些不足,比如我的登录验证是使用的明文密码存储来验证。文件的版本管控没有搭配git。
评论(0)