Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQLAlchemy: Override relationship-defined "order_by" in a query

So, I have a model that is something like:

class Foo(model):
    __tablename__ = "foo"
    id = Column(Integer, primary_key=True)
    data = relationship(
        "FooData",
        cascade="all, delete-orphan",
        backref="foo",
        lazy="dynamic",
        order_by="desc(FooData.timestamp)"
    )

    @property
    def first_item(self):
        # the problem is here:
        return self.data.order_by(asc("timestamp")).first()

    @property
    def latest_item(self):
        return self.data.first()


class FooData(Model):
    __tablename__ = "foo_data"
    foo_id = Column(Integer, ForeignKey("foo.id"), primary_key=True)
    timestamp = Column(DateTime, primary_key=True)
    actual_data = Column(Float, nullable=False)

So, the problem is with the first_item method there: when it is defined as above, the SQL looks like this:

SELECT foo_data.timestamp AS foo_data_timestamp, foo_data.actual_data AS foo_data_actual_data, foo_data.foo_id AS foo_data_foo_id 
FROM foo_data 
WHERE :param_1 = foo_data.foo_id ORDER BY foo_data.timestamp DESC, foo_data.timestamp ASC
--                                                                 ^^^^^^^^^^^^^^^^^^^^^^

Obviously, the order_by specified in the query is being appended to the one specified in the relationship definition, instead of replacing it; is there a way for a query to override the original order_by? I know I could specify a separate query directly on the FooData class, but I would like to avoid that if possible.

like image 236
Berislav Lopac Avatar asked Sep 28 '15 17:09

Berislav Lopac


People also ask

How does SQLAlchemy define relationship in flask?

The comments class attribute defines a One-to-Many relationship between the Post model and the Comment model. You use the db. relationship() method, passing it the name of the comments model ( Comment in this case). You use the backref parameter to add a back reference that behaves like a column to the Comment model.

What is lazy true in SQLAlchemy?

Lazy parameter determines how the related objects get loaded when querying through relationships. Below listed are the four main lazy parameters. Typically when you query the database, the data get loaded at once; however, lazy parameter allows you to alternate the way they get loaded. lazy = 'select' (or True)

What is Primaryjoin?

primaryjoin – A SQL expression that will be used as the primary join of the child object against the parent object, or in a many-to-many relationship the join of the parent object to the association table.

What is Backref in SQLAlchemy?

In Flask-SQLAlchemy, the backref parameter in relationship method allows you to declare a new property under a specified class as seen in the example in their docs: class Person(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50)) addresses = db.relationship('Address', backref='person ...


1 Answers

According to documentation:

All existing ORDER BY settings can be suppressed by passing None - this will suppress any ORDER BY configured on mappers as well.

So the simple solution is to reset ORDER BY clause and then apply the one you need. Like:

self.data.order_by(None).order_by(asc("timestamp")).first()

In case you don't want to reset whole ORDER BY clause, but only want to override one column order, AFAIK there is no built-in way for it.

like image 146
Yaroslav Admin Avatar answered Oct 31 '22 02:10

Yaroslav Admin