

# this make sure our query doesn't break when we run it with raise_errors=False, and Models_to_join, raise_errors=raise_errors Self, _status = self.join_models_if_not_already_joined( Model, attribute_name, models_to_join = parsed

from typing import Mappingĭef magic_filter(self, filters: Mapping, raise_errors: bool = True): Make it easy and fast to add to any route of your application.īefore jumping into the parsing part, let’s have an overview of our own implementation of flask_sqlalchemy’s BaseQuery object, to have a better understanding of the inputs and outputs of the code.Converting these into an SQLAlchemy query.Parsing the parameters to extract its components (field name, operator, value).To engineer this solution, it is very easy to split it into 3 main parts: Now that the context is set, we can dive into the code part. Let’s imagine we have an object that has an owner relation to its owner ?owner_name_like=%john this would return the objects whose authors have a name starting with john. This is done by using _ between the relationship name and its field. In addition to this, we wanted to be able to filter on relationships fields. ?unit_price_~gt=20 would match the unit_prices that are not greater than 20. We also chose the ~ character to specify if we want to negate the operation. ?unit_price_gte=20 would return the entities having an unit_price greater or equal to 20, etc.įor simplicity reasons, we decided that not providing an operator would fallback on the equality operator, making ?name_eq=mindee the same as ?name=mindee.?name_eq=mindee would be an exact match on the name being mindee.

Inspired by a coworker that was a Django fan at the time, the convention we chose consists of using _ as a separator in the parameter key, between the field name and the operator. operator ( in, eq, not, gte, lte, gt, lt, like, …).Query parameters only having a key and a value, we had to find a format giving us the ability to specify: When it comes to API filtering, the most intuitive way of doing this is to use query parameters. Note: All code snippets in this article are compatible with python3.8 or higher and use isort & black for formatting) Query Parameters That said, this article will focus on dynamic API filtering rather than pagination or order, which may be the subject of a separate blog post in the future, then we’ll see how we used it to make it easily usable on any of our applications’ routes. At Mindee, we looked into the different solutions but ultimately decided to build our own logic to make it more flexible for our use-cases without adding another external dependency.

There is no built-in way or best practices for implementing those in the Flask / SQLAlchemy ecosystem, though many packages propose their own solutions. When building REST APIs, we usually focus on three key user-experience concepts: Filtering, Pagination, and Ordering.
