|
我有一个使用SA的 association_proxy 建模 的多对多( @2 z( m& E6 j8 U3 W! i6 k
(开发人员和项目)关系。集合(每个项目的开发人员和每个开发人员的项目)工作正常,但我需要过滤关联本身的属性(状态)。像这样的东西(不起作用): __+ C. B; G. M) {9 E9 y; [5 M* ^
activeDevelopers = s.query(Developer).filter_by(Developer.developerProjects.status == 'active').all()% C# H/ U) _1 f( e& p& F
我想念什么?这是完整的测试代码:
% R& p3 j9 ^9 V# J( S( i! q' p$ _import logging' z3 }7 x% I) W" v9 F, P. L
from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData, ForeignKey
+ [# K6 n: p: Q5 Vfrom sqlalchemy.orm import relation, mapper, sessionmaker, U4 `2 o! a; `" g w0 G- w
from sqlalchemy.sql import *
( E ^! ?9 z+ i/ `from sqlalchemy.ext.associationproxy import association_proxy, }% `* ~6 \ l) U
log = logging.getLogger('nm_test')
, y5 m1 _7 q" f6 L" M! {logging.basicConfig(level=logging.DEBUG,
* L9 b/ D* I. c/ D! L0 H/ ? format='%(asctime)s,%(msecs)03d %(levelname)s [%(filename)s.%(funcName)s @ %(lineno)d.%(thread)d] %(message)s')9 p; {7 c9 ~/ Z8 m+ R1 e8 l/ k, M
engine = create_engine('sqlite:///:memory:', echo = False, echo_pool = False). D* }6 u H$ g# Z+ j5 t
meta = MetaData()
* _6 j d) \& _% [) I# emeta.bind = engine: I2 m5 w7 ^8 w9 r5 R: \% m q
developer_table = Table('developer', meta,/ D% u( l \2 t# J
Column('id', Integer, primary_key=True, autoincrement = False),/ {- t; @: e8 D, E! o" L* P
Column('name', String),3 J6 L6 @8 h8 J+ E" s; l' x% G0 @
)
6 c( ?% P) K7 \1 \: ]; |) a Nproject_table = Table('project', meta,' D8 [/ x0 C1 J, [7 B8 g
Column('id', Integer, primary_key=True, autoincrement = True),0 d! e* N. v v/ K9 }8 {: t! _/ N
Column('name', String)
3 x) v; z" Y9 H0 a)
# {5 P- K9 c2 Vdeveloper_project_table = Table('developer_project', meta,6 w6 f* J+ x# z$ f
Column('developer_id', Integer, ForeignKey('developer.id'), primary_key = True),# Q6 M! T5 D& j. o/ B: N
Column('project_id', Integer, ForeignKey('project.id'), primary_key = True),5 ^/ o' a8 q! X8 y" N' s
Column('status', String)
3 v* ]/ W" b3 h)
& j. e4 _1 d& [, }! oclass Developer(object):
' U( l0 {: h3 d) w; ]& k projects = association_proxy('developerProjects', 'projects'), `- v# C+ w: H" X
def __str__(self):
' _* d. f# u% \. m& U9 h return 'Developer id:%i, name:%s' % (self.id, self.name)* W6 ]6 i0 }* V4 L0 w. \
class Project(object):1 P/ N+ Z0 A% f* }: Z) M
developers = association_proxy('developerProjects', 'developers')
$ n* F6 U' p9 _: M6 O2 J$ d4 _ def __str__(self):4 ]: K/ L+ k7 E# l5 U
return 'Project id:%i, name:%s' % (self.id, self.name)/ @' s6 H6 Y+ _5 p; h( i
class DeveloperProject(object):0 u$ Y! j$ T5 E+ i, z& m- l4 w1 o
def __str__(self):
* w& {: H! e; ^3 ?2 w% c; Z3 n6 } return 'DeveloperProject developer:%s, project:%s, status:%s' % (self.developer_id, self.project_id, self.status)
) K) m; R* X$ p( ~mapper(Developer, developer_table, properties = {" {' }7 J/ [" E# B1 n
'developerProjects':relation(DeveloperProject, backref = "developers")! t# ?$ |; E" u
})
- \' S. Q4 i0 u* {mapper(Project, project_table, properties = {
: x) N* w9 P7 P9 l 'developerProjects':relation(DeveloperProject, backref = "projects")3 D" c9 T" E- ~
})
# j! v6 S, { _: j1 e9 Imapper(DeveloperProject, developer_project_table)
# F; Z: _' n' G0 @, b5 `% w4 Pmeta.create_all(engine)
: v" `# g- u a& X& L* dconn = engine.connect()% v% J) D% J/ ]9 h8 u; |0 L
conn.execute(project_table.insert(),[
: L3 ^: _3 r3 V$ N {'name':'stackoverflow'},
1 y) [; o: Z1 p2 S' I: n7 `4 A {'name':'superuser'},. j, n9 {- B$ g. P% j
])
3 a( s D" u9 _5 lconn.execute(developer_table.insert(),[
- {( R$ u* P9 T1 w/ s% o {'name':'John'},7 y1 O5 _" H" X: h# B/ u V/ M
{'name': 'TerryJ'},7 q$ x$ m/ i, V4 R( K% D& n
{'name': 'TerryG'},( t2 r3 K* k( j' U m
{'name': 'Eric'},( Y* o/ V: m4 V, i/ z
{'name': 'Graham'},# @3 M, F+ l! }/ R& M) \
]) i5 K* u" Z( q t
conn.execute(developer_project_table.insert(),[5 s- }$ g& C3 y" r. h+ w! i
{'developer_id':1, 'project_id':1, 'status':'active'},* o: Y# n/ n- b1 t m
{'developer_id':2, 'project_id':2, 'status':'inactive'},' q$ C/ @' ]" N, X
{'developer_id':3, 'project_id':2, 'status':'active'},
G5 a" Z8 r5 w$ j" k# ? {'developer_id':4, 'project_id':1, 'status':'active'},/ f6 o2 `# v9 n+ T2 o/ w
{'developer_id':4, 'project_id':2, 'status':'active'},/ c' C2 [2 m, R+ p$ q* {6 |8 z" Q
{'developer_id':5, 'project_id':1, 'status':'active'},) u9 P$ k/ i8 {! H3 i* Q8 U
{'developer_id':5, 'project_id':2, 'status':'inactive'},/ x" D' s: x8 O L8 t3 P) b
])# G& f r" S/ u' C: X! n
Session = sessionmaker(bind=engine)
4 Y9 ~1 w% @9 i/ ^7 F0 @, is = Session()
: v8 O$ g1 M8 p$ C/ T/ ldevelopers = s.query(Developer).all()
E/ K9 E" d. w1 b! _projects = s.query(Project).all(); a7 V; V9 k# P! `0 c" p
for d in developers:
: C# g% ~* J2 n( J" i: K2 b+ ` log.debug(d)% [$ ^$ J% x' G6 U+ t
for p in d.projects:' `+ x& J. e0 J7 E3 }; D) h
log.debug(' %s' % p)
' L4 `+ N h, m( n9 Y* w0 w" Xfor p in projects:4 y$ u2 y7 W$ H* _0 Z
log.debug(p)
. |( _6 L. M: ~; M7 [9 Z W for d in p.developers:. K& |. R7 @1 N" C3 h! @
log.debug(' %s' % d)
5 t+ U2 Y5 V6 k* H# does not work% z+ ~) m5 E1 ]% k
activeDevelopers = s.query(Developer).filter_by(Developer.developerProjects.status == 'active').all()& z, _6 d4 F/ b5 b% v) q
# AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object has an attribute 'status'
$ {2 q$ `! M6 S - T' D; R: H' d& Q/ p5 Q" e" _
解决方案:& o* Y/ J& K5 y0 Q
+ }- m( z1 R$ L- x) _+ v1 o
0 s9 n+ p2 }2 Q& y6 V
) E6 j; |- ?; h9 O1 p) }3 F 关联代理的使用any()方法:
5 j$ C4 n4 J- B4 gs.query(Developer).filter(Developer.developerProjects.any(status='active')) |
|