Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding custom filtering for relationships ModelConverterBase._prepare_select_options #801

Open
1 task done
maxim-f1 opened this issue Aug 15, 2024 · 0 comments
Open
1 task done

Comments

@maxim-f1
Copy link

Checklist

  • There are no similar issues or pull requests for this yet.

Is your feature related to a problem? Please describe.

I want to filter relationships in a query, but I can't because the ModelConverterBase._prepare_select_options function generates the query in a hardcode.

Describe the solution you would like.

class CustomModelConverter(ModelConverter):
    select_option_stmts = {
        'field': select(Model).where(Model.level > 1)
    }


class ModelBaseConverter:
    select_option_stmts: Dict[str, Select]
    
    async def _prepare_select_options(
        self,
        prop: RelationshipProperty,
        session_maker: sessionmaker,
    ) -> list[tuple[str, Any]]:
        target_model = prop.mapper.class_
        if prop.key in self.select_option_stmts:
            stmt = self.select_option_stmts[prop.key]
        else:
            stmt = select(target_model)

        if is_async_session_maker(session_maker):
            async with session_maker() as session:
                objects = await session.execute(stmt)
                return [
                    (str(self._get_identifier_value(obj)), str(obj))
                    for obj in objects.scalars().unique().all()
                ]
        else:
            with session_maker() as session:
                objects = await anyio.to_thread.run_sync(session.execute, stmt)
                return [
                    (str(self._get_identifier_value(obj)), str(obj))
                    for obj in objects.scalars().unique().all()
                ]


class View(ModelView, model=Model):
    form_converter = CustomModelConverter

Describe alternatives you considered

There is an option to inherit from ModelConverter and override the _prepare_select_options method in CustomModelConverter. But it looks like a huge crutch.

class CustomModelConverter(ModelConverter):
    async def _prepare_select_options(
       self,
       prop: RelationshipProperty,
       session_maker: sessionmaker,
   ) -> list[tuple[str, Any]]:
       target_model = prop.mapper.class_
       stmt = <custom query>

       if is_async_session_maker(session_maker):
           async with session_maker() as session:
               objects = await session.execute(stmt)
               return [
                   (str(self._get_identifier_value(obj)), str(obj))
                   for obj in objects.scalars().unique().all()
               ]
       else:
           with session_maker() as session:
               objects = await anyio.to_thread.run_sync(session.execute, stmt)
               return [
                   (str(self._get_identifier_value(obj)), str(obj))
                   for obj in objects.scalars().unique().all()
               ]
               
               
class View(ModelView, model=Model):
   form_converter = CustomModelConverter

Additional context

No response

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant