Note that there are some explanatory texts on larger screens.

plurals
  1. POfiltering by association attributes with SqlAlchemy association_proxy
    primarykey
    data
    text
    <p>I have a <em>many-to-many</em> (developers &amp; projects) relationship modeled using SA's <em>association_proxy</em>. The collections (developers on each project &amp; projects for each developer) work fine, but I need to filter on an attribute of the association itself (status). Something like this (which does not work):</p> <pre><code>activeDevelopers = s.query(Developer).filter_by(Developer.developerProjects.status == 'active').all() </code></pre> <p>What am I missing? Here is the complete test code:</p> <pre><code>import logging from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData, ForeignKey from sqlalchemy.orm import relation, mapper, sessionmaker from sqlalchemy.sql import * from sqlalchemy.ext.associationproxy import association_proxy log = logging.getLogger('nm_test') logging.basicConfig(level=logging.DEBUG, format='%(asctime)s,%(msecs)03d %(levelname)s [%(filename)s.%(funcName)s @ %(lineno)d.%(thread)d] %(message)s') engine = create_engine('sqlite:///:memory:', echo = False, echo_pool = False) meta = MetaData() meta.bind = engine developer_table = Table('developer', meta, Column('id', Integer, primary_key=True, autoincrement = False), Column('name', String), ) project_table = Table('project', meta, Column('id', Integer, primary_key=True, autoincrement = True), Column('name', String) ) developer_project_table = Table('developer_project', meta, Column('developer_id', Integer, ForeignKey('developer.id'), primary_key = True), Column('project_id', Integer, ForeignKey('project.id'), primary_key = True), Column('status', String) ) class Developer(object): projects = association_proxy('developerProjects', 'projects') def __str__(self): return 'Developer id:%i, name:%s' % (self.id, self.name) class Project(object): developers = association_proxy('developerProjects', 'developers') def __str__(self): return 'Project id:%i, name:%s' % (self.id, self.name) class DeveloperProject(object): def __str__(self): return 'DeveloperProject developer:%s, project:%s, status:%s' % (self.developer_id, self.project_id, self.status) mapper(Developer, developer_table, properties = { 'developerProjects':relation(DeveloperProject, backref = "developers") }) mapper(Project, project_table, properties = { 'developerProjects':relation(DeveloperProject, backref = "projects") }) mapper(DeveloperProject, developer_project_table) meta.create_all(engine) conn = engine.connect() conn.execute(project_table.insert(),[ {'name':'stackoverflow'}, {'name':'superuser'}, ]) conn.execute(developer_table.insert(),[ {'name':'John'}, {'name': 'TerryJ'}, {'name': 'TerryG'}, {'name': 'Eric'}, {'name': 'Graham'}, ]) conn.execute(developer_project_table.insert(),[ {'developer_id':1, 'project_id':1, 'status':'active'}, {'developer_id':2, 'project_id':2, 'status':'inactive'}, {'developer_id':3, 'project_id':2, 'status':'active'}, {'developer_id':4, 'project_id':1, 'status':'active'}, {'developer_id':4, 'project_id':2, 'status':'active'}, {'developer_id':5, 'project_id':1, 'status':'active'}, {'developer_id':5, 'project_id':2, 'status':'inactive'}, ]) Session = sessionmaker(bind=engine) s = Session() developers = s.query(Developer).all() projects = s.query(Project).all() for d in developers: log.debug(d) for p in d.projects: log.debug(' %s' % p) for p in projects: log.debug(p) for d in p.developers: log.debug(' %s' % d) # does not work activeDevelopers = s.query(Developer).filter_by(Developer.developerProjects.status == 'active').all() # AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object has an attribute 'status' </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload