SQLAlchemy order result by function

This is the code I have and it works (returns all problems, ordered by difficulty):

def get_noteworthy_problems(self):

    ACategory = aliased(Category)
    AProblem = aliased(Problem)

    all_prob = DBSession.query(AProblem).filter(
        AProblem.parent_id == ACategory.id,
        ACategory.parent_id == self.id)

    noteworthy_problems = \
        sorted(all_prob, key=lambda x: x.difficulty(), reverse=True)

    return noteworthy_problems

      

But I think I should optimize this code. Is it possible to change the code with order_by

and my function difficulty()

? My function returns a number. I tried something like:

    result = DBSession.query(AProblem).filter(
        AProblem.parent_id == ACategory.id,
        ACategory.parent_id == self.id).order_by(
        AProblem.difficulty().desc())

      

but I am getting an error TypeError: 'NoneType' object is not callable

.

+3


source to share


1 answer


Hybrid attributes are special methods that act on both a Python property and an SQL expression. As long as your function difficulty

can be expressed in SQL, it can be used for filtering and ordering just like a regular column.

For example, if you are calculating difficulties because the number of parrots has a problem, ten times, if the problem is older than 30 days, you should use:

from datetime import datetime, timedelta
from sqlalchemy import Column, Integer, DateTime, case
from sqlalchemy.ext.hybrid import hybrid_property

class Problem(Base):
    parrots = Column(Integer, nullable=False, default=1)
    created = Column(DateTime, nullable=False, default=datetime.utcnow)

    @hybrid_property
    def difficulty(self):
        # this getter is used when accessing the property of an instance
        if self.created <= (datetime.utcnow() - timedelta(30)):
            return self.parrots * 10

        return self.parrots

    @difficulty.expression
    def difficulty(cls):
        # this expression is used when querying the model
        return case(
            [(cls.created <= (datetime.utcnow() - timedelta(30)), cls.parrots * 10)],
            else_=cls.parrots
        )

      



and request it with:

session.query(Problem).order_by(Problem.difficulty.desc())

      

+4


source







All Articles