flask/django 动态查询表结构相同表名不同数据的Model实现方法
1.问题
为了控制数据的增长,经常需要分表,数据库中存在多张结构相同,表名相关的表,如:
table_201706
table_201707
table_201708
怎么通过SQLAlchemy或者django查询相关的数据表,而不用每次都创建Model呢
2.解决方法
分别在flask和django下实现,代码如下
2.1flask+sqlalchemy
#-*-coding:utf-8 classNewDynamicModel(object): """ 动态产生模型和表的对应关系模型 :parambase_cls:基类模型,虚类,如TemplateModel :paramtb_name:数据库中对应的表名,如tb_test_2017 :return:Modelclass eg: ''' classTemplateModel(db.Model): __abstract__=True id=db.Column(db.Integer(),autoincrement=True,primary_key=True) name=db.Column(db.VARCHAR(32),nullable=False) Test_2017=NewDynamicModel(TemplateModel,'tb_test_2017') printTest_2017.query.all() ''' """ _instance=dict() def__new__(cls,base_cls,tb_name): new_cls_name="%s_To_%s"%( base_cls.__name__,'_'.join(map(lambdax:x.capitalize(),tb_name.split('_')))) ifnew_cls_namenotincls._instance: model_cls=type(new_cls_name,(base_cls,), {'__tablename__':tb_name}) cls._instance[new_cls_name]=model_cls returncls._instance[new_cls_name]
Bug:由于新的数据模型是通过type动态创建的,实际module下的py文件并不存在该类的代码,因而在通过pickle等方式序列化的时候,会报找不到类的错误。
Fixbug:通过inspect库,拷贝基类的代码作为副本,并替换tablename属性,写入临时类定义文件,并引入module。
新的方式实现如下:
classNewDynamicModel(object): """ 动态产生模型和表的对应关系模型 :parambase_cls:基类模型,虚类,如TemplateModel :paramtb_name:数据库中对应的表名,如tb_test_2017 :return:Modelclass eg: ''' classTemplateModel(db.Model): __abstract__=True id=db.Column(db.Integer(),autoincrement=True,primary_key=True) name=db.Column(db.VARCHAR(32),nullable=False) Test_2017=NewDynamicModel(TemplateModel,'tb_test_2017') printTest_2017.query.all() ''' """ @staticmethod defget_import_codes(Model): """ 获取基类的import依赖 :paramModel: :return: """ module=inspect.getmodule(Model) all_codelines=inspect.getsourcelines(module) import_codes=[] import_codes.append('#-*-coding:utf-8\n') foriinall_codelines[0]: match=re.search(r'[from]*[\w|\s]*import[\w|\s]*',i) ifmatch: import_codes.append(i) import_codes.extend(['\n','\n']) returnimport_codes @staticmethod defget_codes(Model,new_model_name,tb_name): """ 获取基类的实现代码 :paramModel: :paramnew_model_name: :paramtb_name: :return: """ codes=inspect.getsourcelines(Model)[0] result=[] has_alias_tb_name=False result.append(codes[0].replace(Model.__name__,new_model_name)) forlineincodes[1:]: match=re.search(r'\s+__tablename__\s+=\s+\'(?P\w+)\'',line) abstract=re.search(r'(?P \s+)__abstract__\s+=\s+',line) ifabstract: delline continue ifmatch: name=match.groupdict()['name'] line=line.replace(name,tb_name) has_alias_tb_name=True result.append(line) ifnothas_alias_tb_name: result.append("%s__tablename__='%s'\n"%('',tb_name)) returnresult @staticmethod defcreate_new_module(module_name,codes): """ 创建新表映射类的module文件 :parammodule_name: :paramcodes: :return: """ f_path=os.path.join(CURRENT_PATH,'_tmp/%s.py'%module_name) fp=open(f_path,'w') foriincodes: fp.write(i) fp.close() returnimport_module('sync_session.models._tmp.%s'%module_name) _instance=dict() def__new__(cls,base_cls,tb_name): new_cls_name="%s_To_%s"%( base_cls.__name__,''.join(map(lambdax:x.capitalize(),tb_name.split('_')))) iftb_namenotinengine.table_names(): raiseTableNotExist ifnew_cls_namenotincls._instance: import_codes=cls.get_import_codes(base_cls) class_codes=cls.get_codes(base_cls,new_cls_name,tb_name) import_codes.extend(class_codes) new_module_name=new_cls_name.lower() new_module=cls.create_new_module(new_module_name,import_codes) model_cls=getattr(new_module,new_cls_name) cls._instance[new_cls_name]=model_cls returncls._instance[new_cls_name]
2.2django
#-*-coding:utf-8 fromdjango.dbimportmodels classNewDynamicModel(object): """ 动态产生模型和表的对应关系模型 :parambase_cls:基类模型,虚类,如TemplateModel :paramtb_name:数据库中对应的表名,如tb_test_2017 :return:Modelclass eg: ''' classTemplateModel(models.Model): id=models.AutoField(primary_key=True) name=models.CharField(max_length=50) classMeta: abstract=True Test_2017=NewDynamicModel(TemplateModel,'tb_test_2017') printTest_2017.objects.all() ''' """ _instance=dict() def__new__(cls,base_cls,tb_name): new_cls_name="%s_To_%s"%( base_cls.__name__,'_'.join(map(lambdax:x.capitalize(),tb_name.split('_')))) ifnew_cls_namenotincls._instance: new_meta_cls=base_cls.Meta new_meta_cls.db_table=tb_name model_cls=type(new_cls_name,(base_cls,), {'__tablename__':tb_name,'Meta':new_meta_cls,'__module__':cls.__module__}) cls._instance[new_cls_name]=model_cls returncls._instance[new_cls_name]
以上这篇flask/django动态查询表结构相同表名不同数据的Model实现方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。