Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQLAlchemy - How can I make eager loading count property

I want to make a property for model which contains count.

Since I always need the property, I want to make query with JOIN like sqlalchemy.orm.relationship with lazy='joined'

For example, I defined models like following

import sqlalchemy as s, func
from sqlalchemy.orm import relatioship

# ...

class Foo(Base):
    __tablename__ = 'foo'
    id = s.Column(s.Integer, primary_key=True)
    bar_id = s.Column(s.Integer, s.ForeignKey('bar.id'))
    bar = relationship('Bar')


class Bar(Base):
    __tablename__ = 'bar'
    id = s.Column(s.Integer, primary_key=True)

    @property
    def foo_count(self):
        return Foo.query.filter_by(bar=self).count()

When I access to property foo_count, then it will send query to DBMS.

Since I always access to this property, I want to load it eagerly the counting property like this

# Not session.query(Bar, func.count(Foo.id)).join(Foo) ...
bar = Bar.query.first()

SQL will be like this

SELECT id, COUNT(Foo.id)
FROM bar 
INNER JOIN foo
    ON bar.id = foo.id

Then bar.foo_count will not occur SQL query.

How can I make a property like foo_count?

like image 677
Choi Geonu Avatar asked Dec 10 '13 06:12

Choi Geonu


People also ask

Why is SQLAlchemy so slow?

Execution Slowness this would indicate that the database is taking a long time to start returning results, and it means your query should be optimized, either by adding indexes or restructuring the query and/or underlying schema.

What is SQLAlchemy lazy loading?

Lazy loading refers to objects are returned from a query without the related objects loaded at first. When the given collection or reference is first accessed on a particular object, an additional SELECT statement is emitted such that the requested collection is loaded.

What is Backref in SQLAlchemy?

The sqlalchemy backref is one of the type keywords and it passed as the separate argument parameters which has to be used in the ORM mapping objects. It mainly includes the event listener on the configuration attributes with both directions of the user datas through explicitly handling the database relationships.

Does SQLAlchemy support batching?

SQLAlchemy supports the widest variety of database and architectural designs as is reasonably possible. Unit Of Work. The Unit Of Work system, a central part of SQLAlchemy's Object Relational Mapper (ORM), organizes pending insert/update/delete operations into queues and flushes them all in one batch.


1 Answers

I solved it by using sqlalchemy.orm.column_property

I replaced the foo_count by following

import sqlalchemy as s, func, select
from sqlalchemy.orm import relationship, column_property

# ...

class Foo(Base):
    __tablename__ = 'foo'
    id = s.Column(s.Integer, primary_key=True)
    bar_id = s.Column(s.Integer, s.ForeignKey('bar.id'))
    bar = relationship('Bar')


class Bar(Base):
    __tablename__ = 'bar'
    id = s.Column(s.Integer, primary_key=True)

    foo_count = column_property(
        select([func.count(Foo.id)])
        .where(Foo.bar_id == id)
    )
like image 152
Choi Geonu Avatar answered Nov 15 '22 17:11

Choi Geonu