Flask Admin apply filters en masse as "Advanced Search" Flask Admin apply filters en masse as "Advanced Search" flask flask

Flask Admin apply filters en masse as "Advanced Search"


Alright, things are about to get ugly, so hold onto your hat.

This is what I ended up writing to accomplish this functionality, and it is code that I am not particularly proud to have written. It works, but that said, please suggest a cleaner way to do this if you feel like it.

Here is the advanced search view:

from flask import flashfrom flask import redirectfrom flask import requestfrom flask import url_forfrom flask_admin import BaseViewfrom flask_admin import exposefrom flask_wtf import FlaskFormfrom flask_login import current_userfrom app import adminfrom .forms import PaperSearchFormclass AdvancedPaperSearchView(BaseView):    form_base_class = FlaskForm    def __init__(self,                 name=None,                 category=None,                 endpoint=None,                 url=None,                 template='auth/model/paper/advanced_search.html',                 menu_class_name=None,                 menu_icon_type=None,                 menu_icon_value=None                 ):        super(AdvancedPaperSearchView, self).__init__(            name,            category,            endpoint,            url or '/',            'static',            menu_class_name=menu_class_name,            menu_icon_type=menu_icon_type,            menu_icon_value=menu_icon_value)        self._template = template    def is_visible(self):        return False    def is_accessible(self):        if current_user.is_authenticated:            return current_user.can_view_papers()        return False    @expose('/', methods=['GET', 'POST'])    def index(self):        form = PaperSearchForm()        form.return_url.data = request.args['return_url']        self._template_args['form'] = form        self._template_args['cancel_url'] = request.args['return_url']        return self.render(self._template)    @expose('/search', methods=['POST'])    def search(self):        form = PaperSearchForm()        # The goal here is to get the paper model view from the currently running app (and its admin extension). Once        # the model view is here, use it to get the available filters (get their keys and operations). Use the existing        # request args and add filters to them using the key and operations defined in the model view.        paper_model_view = None        for view in admin._views:            # There must be a better way to do this, and I know this is a WTF, but I don't have the vocabulary to search            # the flask admin documentation for the right way to get the instance of the model view from the admin            # object. I need the *instance*, with the filters created and added to that instance by the init... so...            # not clean or pretty ... and permanently restricts name of paper model view ... TODO: Fix? Rewrite?            # - Chris, March 2017            if "PaperModelView object" in view.__repr__():                paper_model_view = view        # ._filters contains the list of all  filters        # ._filter_args contains a dictionary of keys and filter objects for url construction        # each filter is persisted with request.args, the query string is <flt[position]_[key]=[value]> or        # <flt[position]_[key]> for filters without values        # The filter is accessed by looking up the filter object with the key value, and then the filters are listed        # in the order of the position provided in the query string. I am unsure whether or not they are applied in        # this order, but that seems like what is happening.        filters = {}        i = 0        str = "flt{pos}_{key}"        def __check(column, table, filter):            return (column in filter.column.name and table in filter.column.table.name.__repr__())        # Sorry for this...        # Iterate through each filter available for the view. Check if it's name and operation are something that        # will enact a portion of the search, then add it's filter (in the format expected) to a dictionary. The index        # variable i keeps track of the "count" of filters that have been added and uses this as the position of the        # filter.        for key, key_filter in paper_model_view._filter_args.items():            filter = key_filter[1]            if hasattr(filter, 'column'):                if __check("title", "papers", filter):                    if "FilterLike" in filter.operation.__repr__():                        if form.title.data:                            filters[str.format(pos=i, key=key)] = form.title.data                            i += 1                if __check("abstract", "papers", filter):                    if "FilterLike" in filter.operation.__repr__():                        if form.abstract.data:                            filters[str.format(pos=i, key=key)] = form.abstract.data                            i += 1                if __check("publication_date", "journal_paper", filter):                    if "DateSmaller" in filter.operation.__repr__():                        if form.end_date.data:                            filters[str.format(pos=i, key=key)] = form.end_date.data.date()  # Only keeps the date for the filter                            i += 1                    elif "DateGreater" in filter.operation.__repr__():                        if form.start_date.data:                            filters[str.format(pos=i, key=key)] = form.start_date.data.date()                            i += 1                if __check("doi", "papers", filter):                    if "FilterLike" in filter.operation.__repr__():                        if form.doi.data:                            filters[str.format(pos=i, key=key)] = form.doi.data                            i += 1                if __check("pubmed_id", "papers", filter):                    if "FilterLike" in filter.operation.__repr__():                        if form.pubmed_id.data:                            filters[str.format(pos=i, key=key)] = form.pubmed_id.data                            i += 1                if __check("link", "papers", filter):                    if "FilterLike" in filter.operation.__repr__():                        if form.link.data:                            filters[str.format(pos=i, key=key)] = form.link.data                            i += 1                if __check("name", "journal", filter):                    if "FilterLike" in filter.operation.__repr__():                        if form.journals.data:                            for journal in form.journals.data:                                filters[str.format(pos=i, key=key)] = journal.name                                i += 1                if __check("first_name", "authors", filter):                    if "FilterLike" in filter.operation.__repr__():                        for author in form.authors.data:                            filters[str.format(pos=i, key=key)] = author.first_name                            i += 1                if __check("last_name", "authors", filter):                    if "FilterLike" in filter.operation.__repr__():                        for author in form.authors.data:                            filters[str.format(pos=i, key=key)] = author.last_name                            i += 1                if __check("keyword", "keywords", filter):                    if "FilterLike" in filter.operation.__repr__():                        for keyword in form.keywords.data:                            filters[str.format(pos=i, key=key)] = keyword.keyword                            i += 1                if __check("name", "chapters", filter):                    if "FilterLike" in filter.operation.__repr__():                        for chapter in form.chapters.data:                            filters[str.format(pos=i, key=key)] = chapter.name                            i += 1                if __check("printed", "chapter_paper", filter):                    if "FilterEqual" in filter.operation.__repr__():                        if form.printed.data == True:                            if form.unprinted.data == False:  # Printed only                                filters[str.format(pos=i, key=key)] = 1  # True                                i += 1                            else:                                pass # Both are True                        else:                            if form.unprinted.data == True:  # Unprinted only                                filters[str.format(pos=i, key=key)] = 0  # False                                i += 1                            else:                                pass # Both are False                else:                    continue        flash('Filters successfully applied', 'success')        return redirect(url_for('paper.index_view', **filters))