'SQLAlchemy: How to output a calculated field that takes in parameters from the user as input

I have a model something like this:

class User:
    __tablename__ = "user"

    first_name = Column(String(), nullable=False)
    last_name = Column(String(), nullable=False)

I then have a query like this:

name = ["...", ...]
user_query = (
    db.session.query(User)
    .add_column(case([
        (and_(User.first_name).ilike(f'%{name}%'), User.last_name.ilike(f'%{name}%')), True),
        (or_(User.first_name).ilike(f'%{name}%'), User.last_name.ilike(f'%{name}%')), False)
    ]).label('perfect_match'))
    .order_by(literal_column("'perfect_match'"))
)

This is obviously an over-simplification, but essentially I'm trying to do a search across fields and sort the perfect matches separately from the imperfect matches.

This is giving me an error saying that the column "perfect_match" doesn't exist, so I think I'm using add_column incorrectly here.

I also tried using hybrid_method like so:

@hybrid_method
def perfect_match(self, terms):
    perfect_match = True
    matched = False
    for term in terms:
        if term.lower() in self.first_name.lower() or term.lower() in self.last_name.lower():
            matched = True
            continue
        perfect_match = False

    return perfect_match if matched else None

@perfect_match.expression
def perfect_match(self, terms):
    perfect_match = and_(...)
    imperfect_match = or_(...)

    return case(...)

And then my query looks like this:

name = [...]
user_query = (
    db.session.query(User)
    .filter(User.perfect_match(name) != None)
    .order_by(User.perfect_match(name))

I want perfect_match to be in the output. Here's my desired SQL:

SELECT
    first_name,
    last_name,
    case (
        ...
    ) as perfect_match
FROM user
WHERE perfect_match != NULL
ORDER BY perfect_match

The first using add_column gives me that SQL, but SQLAlchemy errors saying it can't column perfect_match does not exist. The second (using hybrid_method) puts the case in the WHERE and ORDER BY clauses (probably inefficient?) and doesn't include perfect_match in the output, but it does seem to be working properly. I need to use that output column to determine where the perfect matches end.

I've tried:

  • adding perfect_match as a Column(Boolean)
  • adding perfect_match as a column_property()
  • adding perfect_match as .query(User, literal_column("'perfect_match'"))

Any thoughts? Most of the examples I've seen use hybrid_property, but I need to take in an argument here. I'm pretty new to SQLAlchemy, so I probably missed something.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source