為了學(xué)習(xí)統(tǒng)一處理model的CRUD,所以學(xué)習(xí)一下 flask-admin的實(shí)現(xiàn)方式
使用visual studio 打開 flask-admin 搓幌, 找到了model/base.py
發(fā)現(xiàn)了BaseModelView
類,其中
def create_model(self, form):
raise NotImplementedError()
def update_model(self, form, model):
raise NotImplementedError()
def delete_model(self, model):
raise NotImplementedError()
可見基類沒有實(shí)現(xiàn)中跌,實(shí)現(xiàn)在子類中毯辅,查找一下BaseModelView
有哪些子類
crontrib/appengine/view.py
NdbModelView # google 云數(shù)據(jù)庫 Ndb 我們被墻,所以不用考慮
DbModelView # google 云數(shù)據(jù)庫 Db
crontrib/pymongo/view.py
ModelView # mongodb實(shí)現(xiàn)仔蝌,即nosql型 數(shù)據(jù)庫的實(shí)現(xiàn)
crontrib/sqla/view.py
ModelView # 通用的sql數(shù)據(jù)庫實(shí)現(xiàn)
所以我們僅看一下 sqla
下的實(shí)現(xiàn)
def create_model(self, form):
"""
Create model from form.
:param form:
Form instance
"""
try:
model = self._manager.new_instance() # self._manager = manager_of_class(self.model) , 相當(dāng)于self.model._sa_class_manager.new_instance() 是sqlachemy中的方法
# TODO: We need a better way to create model instances and stay compatible with
# SQLAlchemy __init__() behavior
state = instance_state(model) # self.model._sa_instance_state
self._manager.dispatch.init(state, [], {})
form.populate_obj(model) # 關(guān)鍵是這行代碼泛领,稍后分析
self.session.add(model)
self._on_model_change(form, model, True) # 調(diào)用的父類的事件,其實(shí)父類事件也是調(diào)用self.on_model_change但依舊未實(shí)現(xiàn)敛惊,子類可以實(shí)現(xiàn)渊鞋。
self.session.commit()
except Exception as ex:
if not self.handle_view_exception(ex):
flash(gettext('Failed to create record. %(error)s', error=str(ex)), 'error')
log.exception('Failed to create record.')
self.session.rollback() # 重要,回滾操作
return False
else: # 這個(gè)else很有意思瞧挤,是try->except->else
self.after_model_change(form, model, True) # 默認(rèn)是空锡宋,可自定義
return model
** form.populate_obj(model) **
# model/fields.py InlineModelFormField
def populate_obj(self, obj, name):
for name, field in iteritems(self.form._fields):
if name != self._pk:
field.populate_obj(obj, name)
# model/fields.py InlineModelFormList
def populate_obj(self, obj, name):
values = getattr(obj, name, None)
if values is None:
return
# Create primary key map
pk_map = dict((get_obj_pk(v, self._pk), v) for v in values)
# Handle request data
for field in self.entries:
field_id = get_field_id(field)
is_created = field_id not in pk_map
if not is_created:
model = pk_map[field_id]
if self.should_delete(field):
self.session.delete(model)
continue
else:
model = self.model()
values.append(model)
field.populate_obj(model, None)
self.inline_view._on_model_change(field, model, is_created)
似乎更多的是view(頁面顯示)邏輯,而本身邏輯很簡單就是getattr