增加model后端
Flask-Admin對與之配合的數據庫模型做了一些假設。 如果要實現自己的數據庫后端,並且Flask-Admin的模型視圖仍可按預期工作,則應注意以下事項:
1) 每一個model必須有主鍵,但不限定數據類型和主鍵名
2) 確保每一個model的屬性都是可以訪問的
在此基礎上,你可以通過繼承BaseMiodelView類來實現數據庫后端的擴展,並實現下面列出的一系列方法:
1 擴展BaseModelView
首先定義一個從BaseModelView派生的新類:
class MyDbModel(BaseModelView): pass
這個類繼承了BaseModelView的__init__方法,它接受一個模型類作為第一個參數。 模型類存儲為屬性self.model,以便其他方法可以訪問它。
現在,為新的類實現以下腳手架方法:
1.1 get_pk_value()
該方法從模型實例中返回一個主鍵值。 在SQLAlchemy后端,它使用scaffold_pk()從模型獲得主鍵,緩存它,然后在需要時從模型返回值。
例子:
class MyDbModel(BaseModelView): def get_pk_value(self, model): return self.model.id
1.2 scaffold_list_columns()
返回列表視圖要展示的列。例子:
class MyDbModel(BaseModelView): def scaffold_list_columns(self): columns = [] for p in dir(self.model): attr = getattr(self.model, p) if isinstance(attr, MyDbColumn): columns.append(p) return columns
1.3 scaffold_sortable_columns()
返回可排序列的字典。 字典中的鍵應該對應於模型的字段名稱。 值應該是那些將用於排序的變量。
例如,在SQLAlchemy后端可以按外鍵字段進行排序。 所以,如果有一個名為user的字段,它是Users表的一個外鍵,並且Users表也有一個名稱字段,那么這個鍵將是user的value將是:Users.name。
如果您的后端不支持排序,則返回None或空字典。
1.4 init_search()
初始化搜索功能。 如果您的后端支持全文搜索,請進行初始化並返回True。 如果您的后端不支持全文搜索,請返回False。
例如,SQLAlchemy后端讀取self.searchable_columns的值,並驗證是否所有字段都是文本類型,如果它們定位到當前的模型(如果不是,則會添加一個連接等)並緩存這些信息以備將來使用。
1.5 scaffold_form()
在模型里定義WTForms表單,例子:
class MyDbModel(BaseModelView): def scaffold_form(self): class MyForm(Form): pass # Do something return MyForm
1.6 get_list()
這個方法應該返回帶有分頁,排序等應用的模型實例列表。
對於SQLAlchemy后端,它看起來像:
1)如果搜索已啟用且提供的搜索值不為空,將會為self.searchable_columns中的每個字段生成LIKE語句
2)如果傳遞過濾值,請使用值調用apply方法:
for flt, value in filters: query = self._filters[flt].apply(query, value)
3)執行查詢獲取數據庫中的總行數(count)
4)如果sort_column被傳遞,會做類似的事情(帶有一些額外的FK邏輯,在這個例子中省略):
if sort_desc: query = query.order_by(desc(sort_field)) else: query = query.order_by(sort_field)
5)應用分頁
6)返回總條數和列表的元組
1.7 get_one()
根據主鍵返回model數據
1.8 create_model()
通過表單創建一個model的實例
1.9 update_model()
更新表單model的實例
1.10 delete_model()
從數據存儲中刪除特定的model數據
1.11 is_valid_filter()
驗證返回的數據是否是有效的
1.12scaffold_filters()
返回一個模型字段的過濾器對象列表。
對於self.column_filters設置中的每個條目,該方法都會被調用一次。
如果后端不知道如何為提供的字段生成過濾器,則應該返回None。
例如:
class MyDbModel(BaseModelView): def scaffold_filters(self, name): attr = getattr(self.model, name) if isinstance(attr, MyDbTextField): return [MyEqualFilter(name, name)]
2,實現過濾
每個模型后端都應該有自己的一組過濾器實現。 在非SQLAlchemy后端不能使用SQLAlchemy模型中的過濾器。 這也意味着不同的后端可能有不同的可用過濾器集合。
過濾器是從BaseFilter派生的類,它實現了至少兩種方法:
1. apply()
2. operation()
apply方法接受兩個參數:查詢對象和來自客戶端的值。 在這里您可以為過濾器類型添加過濾邏輯。
讓我們以SQLAlchemy模型后端為例:
所有SQLAlchemy過濾器都從BaseSQLAFilter類派生。
每個過濾器都實現一個簡單的過濾器SQL操作(如,not like,大於等),並接受一列作為輸入參數。每當模型視圖要將篩選器應用於查詢對象時,它將在具有查詢和值的篩選器類中調用apply方法。 過濾器將應用實際的過濾器操作。
class MyBaseFilter(BaseFilter): def __init__(self, column, name, options=None, data_type=None): super(MyBaseFilter, self).__init__(name, options, data_type) self.column = column class MyEqualFilter(MyBaseFilter): def apply(self, query, value): return query.filter(self.column == value) def operation(self): return gettext('equals') # You can validate values. If value is not valid, # return `False`, so filter will be ignored. def validate(self, value): return True # You can "clean" values before they will be # passed to the your data access layer def clean(self, value): return value
如果您在添加新模型后端時遇到問題,請隨時提問。 此外,如果遇到困難,請嘗試查看SQLAlchemy模型后端並將其用作參考。