I have an admin interface with tags that can be associated with any number of entries. As a demonstration, flaskadmintagdemo should give you an idea of what my side looks like.
I wanted to have a link next to each tag pointing to a filtered list of all entries tagged with that specific tag.
The logic for that is in flask-admin > model > template.py
class LinkRowAction(BaseListRowAction):
def render(self, context, row_id, row):
m = self._resolve_symbol(context, 'row_actions.link')
# string_types = (str, unicode)
if isinstance(self.url, string_types):
url = self.url.format(row_id=row_id)
else:
url = self.url(self, row_id, row)
return m(self, url)
So, we need to amend the column_extra_row_actions
to add a LinkRowAction
that points to the filtered listing of entries:
class TagView(ModelView):
class PostURLObj(str):
"""
Fake str object that fails isinstance(str, unicode) so that we can
access the row object
"""
def __new__(self, cls, row_id, row):
_url = "/admin/?flt0_9=%s" % row.name
return str.__new__(self, _url)
column_extra_row_actions = [
# Cannot use EndpointLinkRowAction since we need access
# to the row object
LinkRowAction(
"glyphicon glyphicon-eye-open fa fa-eye", PostURLObj
),
]
Instanciating a new str
subclassed object - in this case PostURLObj
- will
call <cls>.__new__(args)
, not __init__()
. Took me a while to figure that
out…
But, instead of fixating on working around LinkRowAction
, why not just
implement a more suitable action by subclassing BaseListRowAction
?
class PostRowAction(BaseListRowAction):
def __init__(self, icon_class):
super(PostRowAction, self).__init__()
self.icon_class = icon_class
def render(self, context, row_id, row):
m = self._resolve_symbol(context, 'row_actions.link')
url = "/admin/?flt0_9=%s" % row.name
return m(self, url)
class TagView(ModelView):
column_extra_row_actions = [
PostRowAction(
"glyphicon glyphicon-eye-open fa fa-eye",
),
]
Much easier.