Flask Admin 模型CRUD源代码

2020-02-02  本文已影响0人  友仁恒敬

为了学习统一处理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

上一篇 下一篇

猜你喜欢

热点阅读