flask/django 動態查詢表結構相同表名不同資料的Model實現方法
阿新 • • 發佈:2020-01-09
1.問題
為了控制資料的增長,經常需要分表,資料庫中存在多張結構相同,表名相關的表,如:
table_201706
table_201707
table_201708
怎麼通過SQLAlchemy 或者django查詢相關的資料表,而不用每次都建立Model呢
2.解決方法
分別在flask和django下實現,程式碼如下
2.1 flask+sqlalchemy
# -*-coding:utf-8 class NewDynamicModel(object): """ 動態產生模型和表的對應關係模型 :param base_cls: 基類模型,虛類,如TemplateModel :param tb_name: 資料庫中對應的表名, 如tb_test_2017 :return: Model class eg: ''' class TemplateModel(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') print Test_2017.query.all() ''' """ _instance = dict() def __new__(cls,base_cls,tb_name): new_cls_name = "%s_To_%s" % ( base_cls.__name__,'_'.join(map(lambda x:x.capitalize(),tb_name.split('_')))) if new_cls_name not in cls._instance: model_cls = type(new_cls_name,(base_cls,),{'__tablename__': tb_name}) cls._instance[new_cls_name] = model_cls return cls._instance[new_cls_name]
Bug:由於新的資料模型是通過type動態建立的,實際module 下的py檔案並不存在該類的程式碼,因而在通過pickle等方式序列化的時候,會報找不到類的錯誤。
Fixbug: 通過inspect庫,拷貝基類的程式碼作為副本,並替換tablename 屬性,寫入臨時類定義檔案,並引入module。
新的方式實現如下:
class NewDynamicModel(object): """ 動態產生模型和表的對應關係模型 :param base_cls: 基類模型,虛類,如TemplateModel :param tb_name: 資料庫中對應的表名, 如tb_test_2017 :return: Model class eg: ''' class TemplateModel(db.Model): __abstract__ = True id = db.Column(db.Integer(),nullable=False) Test_2017 = NewDynamicModel(TemplateModel,'tb_test_2017') print Test_2017.query.all() ''' """ @staticmethod def get_import_codes(Model): """ 獲取基類的import依賴 :param Model: :return: """ module = inspect.getmodule(Model) all_codelines = inspect.getsourcelines(module) import_codes = [] import_codes.append('# -*-coding:utf-8\n') for i in all_codelines[0]: match = re.search(r'[from]*[\w|\s]*import [\w|\s]*',i) if match: import_codes.append(i) import_codes.extend(['\n','\n']) return import_codes @staticmethod def get_codes(Model,new_model_name,tb_name): """ 獲取基類的實現程式碼 :param Model: :param new_model_name: :param tb_name: :return: """ codes = inspect.getsourcelines(Model)[0] result = [] has_alias_tb_name = False result.append(codes[0].replace(Model.__name__,new_model_name)) for line in codes[1:]: match = re.search(r'\s+__tablename__\s+=\s+\'(?P<name>\w+)\'',line) abstract = re.search(r'(?P<indent>\s+)__abstract__\s+=\s+',line) if abstract: del line continue if match: name = match.groupdict()['name'] line = line.replace(name,tb_name) has_alias_tb_name = True result.append(line) if not has_alias_tb_name: result.append("%s__tablename__ = '%s'\n" % (' ',tb_name)) return result @staticmethod def create_new_module(module_name,codes): """ 建立新表對映類的module檔案 :param module_name: :param codes: :return: """ f_path = os.path.join(CURRENT_PATH,'_tmp/%s.py' % module_name) fp = open(f_path,'w') for i in codes: fp.write(i) fp.close() return import_module('sync_session.models._tmp.%s' % module_name) _instance = dict() def __new__(cls,''.join(map(lambda x: x.capitalize(),tb_name.split('_')))) if tb_name not in engine.table_names(): raise TableNotExist if new_cls_name not in cls._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 return cls._instance[new_cls_name]
2.2 django
# -*-coding:utf-8 from django.db import models class NewDynamicModel(object): """ 動態產生模型和表的對應關係模型 :param base_cls: 基類模型,虛類,如TemplateModel :param tb_name: 資料庫中對應的表名, 如tb_test_2017 :return: Model class eg: ''' class TemplateModel(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=50) class Meta: abstract = True Test_2017 = NewDynamicModel(TemplateModel,'tb_test_2017') print Test_2017.objects.all() ''' """ _instance = dict() def __new__(cls,tb_name.split('_')))) if new_cls_name not in cls._instance: new_meta_cls = base_cls.Meta new_meta_cls.db_table = tb_name model_cls = type(new_cls_name,{'__tablename__': tb_name,'Meta': new_meta_cls,'__module__': cls.__module__}) cls._instance[new_cls_name] = model_cls return cls._instance[new_cls_name]
以上這篇flask/django 動態查詢表結構相同表名不同資料的Model實現方法就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。