2010-12-31 16 views
10

Tengo -muchos-a-muchos (desarrolladores & proyectos) relación de modelado utilizando SA association_proxy. Las colecciones (desarrolladores en cada proyecto & proyectos para cada desarrollador) funcionan bien, pero necesito filtrar un atributo de la asociación en sí (estado). Algo como esto (que no funciona):filtrado por asociación con atributos sqlalchemy association_proxy

activeDevelopers = s.query(Developer).filter_by(Developer.developerProjects.status == 'active').all() 

¿Qué me falta? Aquí está el código de prueba completa:

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' 

Respuesta

9

Uso any() method de la asociación de proxy:

s.query(Developer).filter(Developer.developerProjects.any(status='active')) 
+0

Gracias, funciona bien. – Hollister

+1

¿Cómo se usa 'me gusta' para emparejar en este escenario? –

4

Para añadir a la respuesta de Denis:

Cuando probé el método any(), tengo este error

sqlalchemy.exc.InvalidRequestError: 'any()' not implemented for scalar attributes. Use has(). 

Usando has() en lugar de any() funcionó para mí.

Parece que any() es para relaciones de lista (en este caso, los desarrolladores tienen potencialmente varios proyectos, por lo que Developer.developerProjects es una lista). Mientras que has() es para una relación única (por ejemplo, si un Developer tenía un Workplace asociado).

Aquí está el enlace a la documentación: http://docs.sqlalchemy.org/en/latest/orm/internals.html#sqlalchemy.orm.properties.RelationshipProperty.Comparator.has

Cuestiones relacionadas