hello,

thank you a lot for your answer.

I modified my request and now it compiles, but I do not get the expected 
result...
the method should stop when it encounters a 'Territoire' which is 'region', 
but it lists all the elements, even those of scale (type) 'ville' (I mean 
town) which shhould be removed from the result.

here is a small code reproducing the error:

from sqlalchemy import Column, Integer, String, ForeignKey, create_engine
from sqlalchemy import Column, Integer, String, ForeignKey, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, sessionmaker, aliased
from sqlalchemy.schema import Table

Base = declarative_base()

parent_child = Table('parent_child', Base.metadata,
 Column('parent_id', ForeignKey('territoire.id'), primary_key=True),
 Column('child_id', ForeignKey('territoire.id'), primary_key=True))


class Territoire(Base):
 __tablename__ = 'territoire'
 id = Column(Integer, primary_key=True)
 name = Column(String)
 scale = Column(String)

 children = relationship(
 'Territoire',
 secondary=parent_child,
 back_populates='parents',
 primaryjoin=parent_child.c.parent_id == id,
 secondaryjoin=parent_child.c.child_id == id,

 )

 parents = relationship(
 'Territoire',
 secondary=parent_child,
 primaryjoin=parent_child.c.child_id==id,
 secondaryjoin=parent_child.c.parent_id==id,
 back_populates='children'
 )

 def __repr__(self):
 chaine1= "<Territoire(%s // %s // %s)>" % (self.id, self.name, self.scale)
 return chaine1

 def __init__(self, name, scale):
 self.name = name
 self.scale = scale
 self.parents=[]
 self.children=[]


if __name__ == "__main__":
 engine = create_engine('postgresql://postgres:admin@localhost/territoires2', 
echo=True)
 # Base = declarative_base()
 Session = sessionmaker(bind=engine)
 Session.configure(bind=engine)
 Base.metadata.create_all(engine)
 session = Session()

 # print("territoire table="+Territoire.__table__)
 france = Territoire(name="france", scale="pays")
 metz = Territoire(name='metz', scale='ville')
 grand_est = Territoire(name='Grand Est', scale='region')

 metz.parents.append(grand_est)
 grand_est.parents.append(france)
 var = Territoire('Var', 'region')
 france.children.append(var)
 sete = Territoire('sete', 'ville')
 var.children.append(sete)
 session.add_all([france, metz, grand_est])
 session.add_all([var,sete])

 # +++++++++++++++++++++++

 # **********************************************
 session.commit()
 # **********************************************

 # for t in session.query(Territoire):
 # print(t)

 element0 = aliased(Territoire)
 sub_territories = session.query(element0.id,element0.name,element0.scale). \
 filter(element0.id == 1). \
 filter(element0.scale != 'region'). \
 cte(name='sub_territories', recursive=True)

 # st_alias = aliased(sub_territories,name="sa")
 relation = aliased(parent_child, name="rel")
 porteur = aliased(Territoire, name="p")
 rec=aliased(sub_territories,name="rec")

 sub_territories = sub_territories.union(
 session.query(porteur.id,porteur.name,porteur.scale). \
 # filter(porteur.id == relation.c.child_id). \
 filter(porteur.id == relation.c.child_id). \
 filter(relation.c.parent_id == sub_territories.c.id). \
 filter(sub_territories.c.scale != 'region'))

# sub_territories = sub_territories.union(corps)

print(sub_territories)

q = session.query(Territoire).select_from(sub_territories)
print('solution =' + str(q.all()))

my problem seems to be logical, I will try to solve it, but maybe someone could 
help me to go faster!


thank you






Le dimanche 7 juillet 2019 15:29:19 UTC+2, Olivier SAINT-EVE a écrit :
>
> I created this recursive query:
>
> element0 = aliased(Territoire)
>     sub_territories = session.query(element0, element0.id). \
>         filter(element0.id == 1). \
>         filter(element0.scale != 'Region'). \
>         cte(name='sub_territories', recursive=True)
>
>     st_alias = aliased(sub_territories)
>     relation = aliased(parent_child)
>     porteur = aliased(Territoire)
>
>     corps = session.query(porteur, relation.c.child_id). \
>         join(porteur, porteur.id == relation.c.child_id). \
>         join(st_alias, relation.c.parent_id == st_alias.c.id). \
>         filter(st_alias.c.scale != 'Region')
>
>     sub_territories = sub_territories.union(corps)
>
> which should give all the children of element0 recursively, stopping at 
> the 'Region' level(items are linked by a many-to-many relation), each item 
> having a level which can be : world, country, region, city...
>
> here is some code that could help you:
>
> class Territoire(Base):
>     __tablename__ = 'territoire'
>     id = Column(Integer, primary_key=True)
>     name = Column(String)
>     scale = Column(String)
>
>     children = relationship(
>         'Territoire',
>         secondary=parent_child,
>         back_populates='parents',
>         primaryjoin=parent_child.c.parent_id == id,
>         secondaryjoin=parent_child.c.child_id == id,
>
>     )
>
>     parents = relationship(
>         'Territoire',
>         secondary=parent_child,
>         primaryjoin=parent_child.c.child_id==id,
>         secondaryjoin=parent_child.c.parent_id==id,
>         back_populates='children'
>     )
>
> and the table:
>
> parent_child = Table('parent_child', Base.metadata,
>                      Column('parent_id', ForeignKey('territoire.id'), 
> primary_key=True),
>                      Column('child_id', ForeignKey('territoire.id'), 
> primary_key=True))
>
> the error message is :
>
> sqlalchemy.exc.ArgumentError: All selectables passed to CompoundSelect 
> must have identical numbers of columns; select #1 has 3 columns, select #2 
> has 4
>
> I don't understand this error, since the 2 CTE requests have for 1st 
> element a Territoire object and for 2nd element an int (id).
>
> thank you
>

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/sqlalchemy.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sqlalchemy/abac3ac5-fac3-42f9-aa4f-1f4268b202c2%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to