專案中遇到乙個比較棘手的問題,之前的應用是沒有migrate相關功能的。從下乙個版本起,需要實現應用的資料庫自動公升級。採用的是flask-migrate外掛程式。但是要做migrate的前提是有之前的資料庫版本檔案支撐。
最理想的情況是沒有什麼使用者資料,簡單粗暴的強制使用者重新安裝並且重新建立新的資料庫,這樣以後都可以直接呼叫migrate的相關命令進行公升級。這種做法顯然不是很負責的,雖然真的很想這麼幹。所以!作為乙個負責人的程式設計師!必須解決這樣的讓人頭大的,冷啟動問題。
第一種方案,給使用者下發migrate版本檔案,使用者沒有初始版本,那我們可以在更新包內給使用者乙個!貌似很完美的解決了這個問題。但是!使用者使用的版本,也許大概可能絕對不會只有乙個...下發哪個版本的指令碼檔案?所以該方案不完美。
第二種方案,根據資料庫和普遍orm的特徵,當模型字段少於資料庫欄位時,正常的資料庫操作不受影響。所以,我們可以在做本次公升級之前,保留使用者的全部資料。公升級建立新的資料庫和資料表,再將舊的資料全部匯入。但是!有個問題就是,當orm的字段多於資料庫時,所有的orm操作都會受到影響。假如只支援單資料庫,那麼可以通過資料庫的dumps或者類似命令去直接解決,假如支援使用者自行設定資料庫,這個問題則比較麻煩。好在問題停留在了**層,總歸是可以解決。ok,**這麼搞。
from flask_script import manager
from *** import session_maker, db
import json, os
from datetime import datetime
from sqlalchemy.exc import programmingerror, operationalerror
from modules.database import models
from ***x import g_init_cfg
def get_rows(model, columns=none):
"""獲取資料行
:param model: 模型類
:param columns: 需要獲取的列。因為**model的字段可能多於資料庫表,所以此處的列需要動態剔除不支援的列。
:return: 組裝成字典的資料
"""def inner(model, columns):
"""內部遞迴方法,因資料庫機制,每次拋錯只丟擲乙個錯誤,所以需要遞迴檢查並剔除檢查出的列。直到剩餘的column與資料庫表完全相容。
:param model: 模型類
:param columns: 需要獲取的列
:return: 資料庫資料的元組列表和最終剩餘的有效columns
"""with session_maker() as session:
if not columns:
''' 當columns為空時,預設獲取模型內所有的字段 '''
try:
''' 將字段型別轉化為sqlalchemy支援的型別,並嘗試獲取資料 '''
fields = [getattr(model, column.key) for column in columns]
rows = session.query(*fields).all()
except (programmingerror, operationalerror) as e:
''' 因為各資料庫的錯誤提示不同,根據不同的資料庫引擎分別處理不同的錯誤資訊 '''
engine = g_init_cfg.getengine()
if engine == 'sqlserver':
if 'invalid column name' in e.args[0]:
''' 當提示某字段不存在或者不支援,則記錄並從columns內剔除該欄位 '''
column_name = e.args[0].split('\'')[1]
elif 'invalid object name' in e.args[0]:
''' 當提示當前模型沒有對應資料表,則直接返回空,無需處理 '''
return , columns
elif engine == 'postgresql':
if 'does not exist' in e.orig.diag.message_primary and 'relation' not in e.orig.diag.message_primary:
column_name = e.orig.diag.message_primary.split('.')[1].split()[0]
elif 'does not exist' in e.orig.diag.message_primary and 'relation' in e.orig.diag.message_primary:
return , columns
elif engine == 'sqlite':
if 'no such column' in e.args[0]:
column_name = e.args[0].split('.')[2]
elif 'no such table' in e.args[0]:
return , columns
for i, column in enumerate(columns):
if column.key == column_name:
''' 剔除不支援的字段 '''
columns.pop(i)
''' 因為上文已經出現過報錯,在某些資料庫的引擎中,如postgres的引擎會將execute指令認為是事務,導致之後所有操作均不執行
此處直接關閉session,再遞迴進下一步時重新建立'''
session.close()
''' 遞迴入口 '''
rows, columns = inner(model, columns)
return rows, columns
rows, columns = inner(model, columns)
if rows:
''' 拼裝返回的資料為列表 '''
li =
for row in rows:
mo = dict()
for idx, field in enumerate(list(row)):
if isinstance(field, datetime):
field = field.strftime('%y-%m-%d %h:%m:%s')
mo[columns[idx].key] = field
return li
else:
return
customcommand = manager(help='project auxiliary tool.')
@customcommand.option('-d', '--directory', dest='directory', default='',
help=("json script directory (default is "
"'project home directory')"))
def exports(directory=''):
"""資料匯出 命令
:param directory: 可設定的匯出存放路徑,預設為當前目錄下
:return:
"""''' 獲取所有基於db.model的子類,即所有模型model '''
models = db.model.__subclasses__()
result = dict()
for model in models:
result[model.__name__] = get_rows(model)
f = open(directory + 'models.json', 'w')
f.write(json.dumps(result))
f.close()
print('export data to [%s] success!' % directory + 'models.json')
@customcommand.option('-d', '--directory', dest='directory', default='',
help=("json script directory (default is "
"'project home directory')"))
def imports(directory=''):
"""資料匯入 命令
:param directory: 資料庫檔案的存放路徑,預設為當前目錄下
:return:
"""os.path.exists(directory + 'models.json')
f = open(directory + 'models.json', 'r')
mo_data = f.read()
data = json.loads(mo_data)
for table in data.keys():
if data.get(table):
with session_maker() as session:
instance_li =
for value in data[table]:
instance = getattr(models, table)(**value)
session.add_all(instance_li)
print('import data success!')
注釋齊全。以上。 Activity啟動模式的應用場景
singletop適合接收通知啟動的內容顯示頁面。例如,某個新聞客戶端的新聞內容頁面,如果收到10個新聞推送,每次都開啟乙個新聞內容頁面是很煩人的。singletask適合作為程式入口點。例如瀏覽器的主介面。不管從多少個應用啟動瀏覽器,只會啟動主介面一次,其餘情況都會走onnewintent,並且會...
Activity的啟動模式及應用場景
標籤 空格分隔 activity 1.standard這是預設模式,每次啟用activity時都會建立activity例項,並放入任務棧中。使用場景 大多數activity startactivity activity a activity b activity c back activity c ...
Oracle imp 匯入資料的應用
1.它是作業系統下乙個可執行的檔案 存放目錄 oracle home bin imp匯入工具將exp形成的二進位制系統檔案匯入到資料庫中.它有三種模式 a.使用者模式 匯出使用者所有物件以及物件中的資料 b.表模式 匯出使用者所有表或者指定的表 c.整個資料庫 匯出資料庫中所有物件。只有擁有imp ...