pallets-eco / flask-admin

Simple and extensible administrative interface framework for Flask
https://flask-admin.readthedocs.io
BSD 3-Clause "New" or "Revised" License
5.8k stars 1.58k forks source link

Proposal: add limit search to field using colon syntax #1628

Open kootenpv opened 6 years ago

kootenpv commented 6 years ago

I have created a gist because I usually would really like syntax such as username:kootenpv which would limit the search to that field.

See here how I implemented it: https://gist.github.com/kootenpv/038d58d70fc338ef742c613a39408069

I'm curious if this is already easily possible another way. If not, maybe we can discuss how to add this to flask_admin?

ljluestc commented 4 days ago

from flask_admin.contrib.sqla import ModelView
from flask_admin.model import BaseModelView
from sqlalchemy.orm import Query
from sqlalchemy import or_, and_

class CustomSearchableModelView(ModelView):
    def scaffold_query(self):
        """Override scaffold_query to support field-specific searches."""
        query = super().scaffold_query()
        search_term = self._search_term

        if search_term:
            query = self.apply_custom_search(query, search_term)

        return query

    def apply_custom_search(self, query: Query, search_term: str) -> Query:
        """Parse the search term and apply field-specific searches."""
        # Separate field-specific searches
        terms = search_term.split()
        filters = []

        for term in terms:
            if ':' in term:  # Field-specific search
                field, value = term.split(':', 1)
                if field in self.column_searchable_list:
                    column = getattr(self.model, field, None)
                    if column is not None:
                        filters.append(column.ilike(f"%{value}%"))
            else:  # General search
                general_filters = [
                    getattr(self.model, field).ilike(f"%{term}%")
                    for field in self.column_searchable_list
                ]
                filters.append(or_(*general_filters))

        # Combine all filters
        if filters:
            query = query.filter(and_(*filters))

        return query

    def is_searchable(self):
        """Ensure that search is enabled."""
        return bool(self.column_searchable_list)