jowilf / starlette-admin

Fast, beautiful and extensible administrative interface framework for Starlette & FastApi applications
https://jowilf.github.io/starlette-admin/
MIT License
632 stars 59 forks source link

Bug: searching by id #522

Closed Ilya-Green closed 3 months ago

Ilya-Green commented 8 months ago

Describe the bug Is there ant way to enable searching by id? If i trying to include "id" in "searchable_fields" search starts working incorrect: it stops filtering reccord, but only highlights matches on the current page if they are if or not.

_without "id" in "searchablefields": image image

with "id" in "searchable_fields": image image

To Reproduce

class NotesView(MyModelView):
    fields = [
        Note.id,
        Note.content,
    ]

    searchable_fields = [
        Note.id
    ]

Environment (please complete the following information):

sglebs commented 8 months ago

I have faced the same problem and have the same need to search by an ID (primary key) or the relationship itself. In my case:

class User(Base):
    __tablename__ = 'users'

    id = Column(Text, primary_key=True, default=cuid)
    created_at = Column(TIMESTAMP(timezone=True, precision=3), nullable=False, server_default=text("CURRENT_TIMESTAMP"))
    updated_at = Column(TIMESTAMP(timezone=True, precision=3), nullable=False,  onupdate=current_date_time_with_tz, default=current_date_time_with_tz)
    client_id = Column(ForeignKey('clients.id', ondelete='SET NULL', onupdate='CASCADE'))
    role = Column(Enum(UserRole, name='UserRole'), server_default=text("'REGULAR'::\"UserRole\""))
    name = Column(Text)
    email = Column(Text, nullable=False, unique=True)

    client = relationship('Client')

A User belongs to a Client. I want to search based on the Client (or the Client id if I am forced to, as plan B)

Ilya-Green commented 8 months ago

Possible solution (for sqla): startlette_admin/contrib/sqla/view.py:

    def get_search_query(self, request: Request, term: str) -> Any:
        clauses = []
        for field in self.fields:
            if field.searchable and type(field) in [
                StringField,
                TextAreaField,
                EmailField,
                URLField,
                PhoneField,
                ColorField,
                # there can be added custom fieldsto make them searchable
            ]:
                attr = getattr(self.model, field.name)
                clauses.append(cast(attr, String).ilike(f"%{term}%"))
+       id_clause = cast(self.model.id, String).ilike(f"%{term}%")
+       clauses.append(id_clause)
        return or_(*clauses)

I must warn you that the code on the basis of which I am making changes is old and may differ from the latest version of starlette_admin, but I marked the lines that I added with a plus sign so that the principle would be clear

jowilf commented 3 months ago

You can override the get_search_query method and write your own search query