说明
我也很想一次把数据表结构都设计好
事实证明,唯一不变的就是变化。本篇讨论如何比较灵活的增加Flask的数据的数据对象以应对各种变化。
以新增面对变更
1 不要外键
外键会使得删表比较麻烦,因此我不建议使用外键。当然有少部分特别固定的关系表可以用外键(例如用户角色、用户表)。
2 用jinja模板创建新的对象
创建数据库时字段名是个特别烦人的东西,因此使用jinja模板
datamodel.j2:将固定的变量先创建好,其他的用for循环传入。
class {{classname}}(db.Model):
__tablename__='{{classname|lower}}'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32))
{%for str_var in str_var_list%}{{str_var}}= db.Column(db.String(32))
{%endfor%}
{%for num_var in num_var_list%}{{num_var}}= db.Column(db.Float(precision=2))
{%endfor%}
{%for dt_var in dt_var_list%}{{dt_var}}= db.Column(db.DateTime())
{%endfor%}
对应的python,将新的变量传入
import DataManipulation as dm
# 不传空列表模板参数不处理,不会出错
# report
classname = 'report'
str_var_list = ['report_id','description','tier1', 'tier2', 'tier3']
num_var_list = []
dt_var_list = ['create_time','update_time']
content = dm.gen_by_j2(template_name='datamodel.j2', classname=classname,
str_var_list=str_var_list, num_var_list=num_var_list, dt_var_list=dt_var_list)
with open('tem.py', 'w') as f:
f.write(content)
tem.py ,这部分是结果
class report(db.Model):
__tablename__='report'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32))
varname= db.Column(db.String(32))
description= db.Column(db.String(32))
tag= db.Column(db.String(32))
ref_low= db.Column(db.Float(precision=2))
ref_high= db.Column(db.Float(precision=2))
ord= db.Column(db.Float(precision=2))
create_time= db.Column(db.DateTime())
update_time= db.Column(db.DateTime())
3 使用shell直接创建新对象
使用manage包装后, 可以在终端中启动shell
python3 manager.py shell
在打开的ipython中导入新表(对象),并执行create_all
from app import db
... # 老对象不用清除,不会对已存在的表重新创建
from app.datamodel import report
import dateutil.parser
import pytz
import pandas as pd
import DataManipulation as dm
from collections import OrderedDict
from datetime import datetime
'''
如果做好了迁移可以db.drop_all()再db.create_all()。否则只能create_all()
'''
# 本机上drop all ,服务器上不要
# db.drop_all()
# 新建表
db.create_all()
print('* db create all tables defined in app.datamodel')
4 使用pymysql从外部导入数据
import pandas as pd
import pymysql as pyl
import numpy as np
import DataManipulation as dm
from datetime import datetime
env = 'local'
if env.lower() == 'local':
host = '111.111.111.111'
else:
host = '222.222.222.222'
cfg_mysql = {
"host": host,
"port": 1111,
"user": "aaaa",
"password": "aaaaaaa",
"db": "aaaaaaa"
}
connection = pyl.connect(**cfg_mysql)
with connection.cursor() as cursor:
for i in range(2000, 2030):
tem_sql = "insert into base8v2_reporttype(name, report_id, description,tier1,tier2,tier3, create_time, update_time) values('%s','%s','%s','%s','%s','%s','%s','%s')" % (
str(i) + 'report', 'base8_' + str(i) ,'test report','basic', 'fen', str(i), dt_str, dt_str)
cursor.execute(tem_sql)
connection.commit()
connection.close()
注意connect没有用try的方法,如果插入语句出问题,可能连接要手动关闭(否则影响其他终端例如navicat的操作)
5 使用静态导入表在内部使用(弥补前面不加外键的操作)
因为没有加外键,那么在就在视图开始启动时读入静态表(通常都是映射表,很小)
例如:
report_df = sql_read_table('report')
# 将原始变量名映射为数据库字段名
varname_mapping_dict = dict(zip(list(report_df['name']), list(report_df['varname'])))
这样一个表对象的追加就结束了,根据新表对应的增加视图函数就可以了。
6 续
- sqlalchemy对象在解析时会有点麻烦,所以我们给数据对象加点料,让其可以直接通过dict函数转换为字典
6.1 重新构建jinja模板
data_model1.j2
class {{classname}}(db.Model):
__tablename__='{{classname|lower}}'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32))
{%for str_var in str_var_list%}{{str_var}}= db.Column(db.String(32))
{%endfor%}
{%for num_var in num_var_list%}{{num_var}}= db.Column(db.Float(precision=2))
{%endfor%}
{%for dt_var in dt_var_list%}{{dt_var}}= db.Column(db.DateTime())
{%endfor%}
{#上面部分不动下面加料#}
def keys(self):
return ({%for var in all_var_list%}{%if not loop.first%},{%endif%}'{{var}}'{%endfor%})
def __getitem__(self, item):
return getattr(self, item)
6.2 对应修改一下python
classname = 'report'
default_var_list = ['id', 'name']
str_var_list = ['report_id', 'description', 'tier1', 'tier2', 'tier3']
num_var_list = []
dt_var_list = ['create_time', 'update_time']
all_var_list = default_var_list + str_var_list + num_var_list + dt_var_list
content = dm.gen_by_j2(template_name='datamodel1.j2', classname=classname,
str_var_list=str_var_list, num_var_list=num_var_list, dt_var_list=dt_var_list, all_var_list=all_var_list)
with open('tem.py', 'w') as f:
f.write(content)
6.3 结果(将其拷贝到网站的数据对象定义下面)
tem.py (流程顺畅后也可以直接python文件读取存到report下面)
class report(db.Model):
__tablename__='report'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32))
report_id= db.Column(db.String(32))
description= db.Column(db.String(32))
tier1= db.Column(db.String(32))
tier2= db.Column(db.String(32))
tier3= db.Column(db.String(32))
create_time= db.Column(db.DateTime())
update_time= db.Column(db.DateTime())
def keys(self):
return (id,name,report_id,description,tier1,tier2,tier3,create_time,update_time)
def __getitem__(self, item):
return getattr(self, item)
再之后通过 pyhton3 manager.py shell 中造作创建表。