2

It is a very specific question regarding Flask-appbuilder. During my development, I found FAB's ModelView is suitable for admin role, but need more user logic handlers/views for complex designs.

There is a many to many relationship between devices and users, since each device could be shared between many users, and each user could own many device. So there is a secondary table called accesses, describes the access control between devices and users. In this table, I add "isHost" to just if the user owns the device. Therefore, we have two roles: host and (regular) user. However, these roles are not two roles defined as other applications, since one man can be either host or user in same time. In a very simple application, enforce the user to switch two roles are not very convinient. That makes things worse.

Anyway, I need design some custom handlers with traditional Flask/Jinja2 templates. For example:

class PageView(ModelView):
    # FAB default URL: "/pageview/list"
    datamodel = SQLAInterface(Page)
    list_columns = ['name', 'date', 'get_url']

    @expose("/p/<string:url>")
    def p(self, url):
        title = urllib.unquote(url)
        r = db.session.query(Page).filter_by(name = title).first()

        if r:
            md = r.markdown
            parser = mistune.Markdown()
            body = parser(md)
            return self.render_template('page.html', title = title, body = body)
        else:
            return self.render_template('404.html'), 404

Above markdown page URL is simple, since it is a seperate UI. But if I goes to DeviceView/AccountView/AccessView for list/show/add/edit operations. I realized that I need a unique styles of UI.

So, now how can I reuse the existing templates/widgets of FAB with custom sqlalchemy queries? Here is my code for DeviceView.

class DeviceView(ModelView):
    datamodel = SQLAInterface(Device)
    related_views = [EventView, AccessView]

    show_template = 'appbuilder/general/model/show_cascade.html'
    edit_template = 'appbuilder/general/model/edit_cascade.html'

    @expose('/host')
    @has_access
    def host(self):
        base_filters = [['name', FilterStartsWith, 'S'],]
        #if there is not return, FAB will throw error
        return "host view:{}".format(repr(base_filters))

    @expose('/my')
    @has_access
    def my(self):
        # A pure testing method
        rec = db.session.query(Access).filter_by(id = 1).all()      
        if rec:
            for r in rec:
                print "rec, acc:{}, dev:{}, host:{}".format(r.account_id, r.device_id, r.is_host)
            return self.render_template('list.html', title = "My Accesses", body = "{}".format(repr(r)))
        else:
            return repr(None)

Besides sqlalchemy code with render_template(), I guess base_filters can also help to define custom queries, however, I have no idea how to get query result and get them rendered.

Please give me some reference code or example if possible. Actually I have grep keywords of "db.session/render_template/expoaw"in FAB's github sources. But no luck.

Allan K Liu
  • 493
  • 1
  • 7
  • 23

0 Answers0