为了学习统一处理model的CRUD,所以学习一下 flask-admin的实现方式
使用visual studio 打开 flask-admin , 找到了model/base.py
发现了BaseModelView
类,其中
def create_model(self, form):
raise NotImplementedError()
def update_model(self, form, model):
raise NotImplementedError()
def delete_model(self, model):
raise NotImplementedError()
可见基类没有实现,实现在子类中,查找一下BaseModelView
有哪些子类
crontrib/appengine/view.py
NdbModelView # google 云数据库 Ndb 我们被墙,所以不用考虑
DbModelView # google 云数据库 Db
crontrib/pymongo/view.py
ModelView # mongodb实现,即nosql型 数据库的实现
crontrib/sqla/view.py
ModelView # 通用的sql数据库实现
所以我们仅看一下 sqla
下的实现
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) , 相当于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) # 关键是这行代码,稍后分析
self.session.add(model)
self._on_model_change(form, model, True) # 调用的父类的事件,其实父类事件也是调用self.on_model_change但依旧未实现,子类可以实现。
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: # 这个else很有意思,是try->except->else
self.after_model_change(form, model, True) # 默认是空,可自定义
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