I have one example illustrating that A.b.id does not pick up the correct id

from sqlalchemy import Column, DateTime, String, Integer, ForeignKey,
func, Table, create_engine, join
from sqlalchemy.orm import relationship, backref, sessionmaker,
joinedload, contains_eager, mapper
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()
engine = create_engine('sqlite://', echo=True)


class A(Base):
    __tablename__ = 'a'

    id = Column(Integer, primary_key=True)
    b_id = Column(ForeignKey('b.id'))

class B(Base):
    __tablename__ = 'b'

    id = Column(Integer, primary_key=True)

class C(Base):
    __tablename__ = 'c'

    id = Column(Integer, primary_key=True)
    a_id = Column(ForeignKey('a.id'))

class D(Base):
    __tablename__ = 'd'

    id = Column(Integer, primary_key=True)
    c_id = Column(ForeignKey('c.id'))
    b_id = Column(ForeignKey('b.id'))

# 1. set up the join() as a variable, so we can refer
# to it in the mapping multiple times.
j = join(B, D, D.b_id == B.id).join(C, C.id == D.c_id)


# 2. Create a new mapper() to B, with non_primary=True.
# Columns in the join with the same name must be
# disambiguated within the mapping, using named properties.
B_viacd = mapper(B, j, non_primary=True, properties={
    "b_id": [j.c.b_id, j.c.d_b_id],
    "d_id": j.c.d_id
    })

A.b = relationship(B_viacd, primaryjoin=A.b_id == B_viacd.c.b_id)


Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)
Session = sessionmaker(engine)
session = Session()


# we insert one B object
b = B()
session.add(b)
session.flush()
assert b.id == 1

# we insert one A object
a = A()
a.b_id = b.id
session.add(a)
session.flush()

# we insert two C objects
c = C()
session.add(c)
session.flush()

c2 = C()
c2.a_id = a.id
session.add(c2)
session.flush()

d = D()
d.b_id = b.id
d.c_id = c2.id
session.add(d)
session.flush()

queried_a = session.query(A).one()
assert queried_a.b.id == 1  # fails because b.id = 2 (while it should
be = 1) because we have one B object


Le ven. 28 déc. 2018 à 15:13, Mike Bayer <mike...@zzzcomputing.com> a
écrit :

> On Fri, Dec 28, 2018 at 4:24 AM Mehdi Gmira <mgm...@wiremind.fr> wrote:
> >
> > Thanks for the reply. There is something I don't understand in the
> example:
> >
> > B_viacd = mapper(B, j, non_primary=True, properties={
> >     "b_id": [j.c.b_id, j.c.d_b_id],
> >     "d_id": j.c.d_id
> >     })
> >
> >
> > How Is the mapper supposed to map the results of j with the class B ?
> the statement behind j is:
> >
> >> SELECT d.id AS d_id, b.id AS b_id, d.b_id AS d_b_id, d.c_id AS d_c_id,
> c.id AS c_id, c.a_id AS c_a_id
> >> FROM b JOIN d ON d.b_id = b.id JOIN c ON c.id = d.c_id
> >
> >
> > d.id is mapped to d_id, and b.id to b_id. So I don't understand how the
> ORM can map b.id to B.id.
>
> I think the answer is that they are not, only columns that match up
> with what's established in the primary mapper will be apparent on the
> returned objects.   Id have to check to see exactly what happens.
> But you should be getting the columns that were originally mapped.
> if not, then we need to open an issue with a complete MCVE.
>
>
> >
> > Le ven. 28 déc. 2018 à 00:25, Mike Bayer <mike...@zzzcomputing.com> a
> écrit :
> >>
> >> the section at
> https://docs.sqlalchemy.org/en/latest/orm/join_conditions.html#relationship-to-non-primary-mapper
> >> has a recipe for: "when we seek to join from A to B, making use of any
> >> number of C, D, etc. in between, however there are also join
> >> conditions between A and B directly", I think that's this case because
> >> you have conditions between Game/YearStadium directly.  So I think use
> >> that pattern.
> >>
> >>
> >>
> >> On Thu, Dec 27, 2018 at 6:18 AM <mgm...@wiremind.fr> wrote:
> >> >
> >> > from sqlalchemy import Column, DateTime, String, Integer, ForeignKey,
> func, Table, create_engine
> >> > from sqlalchemy.orm import relationship, backref, sessionmaker,
> joinedload, contains_eager
> >> > from sqlalchemy.ext.declarative import declarative_base
> >> >
> >> > Base = declarative_base()
> >> > engine = create_engine('sqlite://', echo=True)
> >> >
> >> >
> >> > class Game(Base):
> >> >  __tablename__ = 'game'
> >> >
> >> >  id = Column(Integer, primary_key=True)
> >> >
> >> >  stadium_name = Column(String)
> >> >  month_id = Column(Integer, ForeignKey('month.id'))
> >> >
> >> >  year_stadium = relationship("YearStadium", secondary="month",
> >> >  primaryjoin="Month.id == Game.month_id",
> >> >  secondaryjoin="and_(Month.year_name == YearStadium.year_name, "
> >> >  "YearStadium.stadium_name == Game.stadium_name)")
> >> >
> >> >
> >> > class Month(Base):
> >> >  __tablename__ = 'month'
> >> >
> >> >  id = Column(Integer, primary_key=True)
> >> >
> >> >  year_name = Column(String)
> >> >
> >> >
> >> > class YearStadium(Base):
> >> >  __tablename__ = 'year_stadium'
> >> >
> >> >  id = Column(Integer, primary_key=True)
> >> >
> >> >  stadium_name = Column(String)
> >> >  year_name = Column(String)
> >> >
> >> >
> >> > Base.metadata.drop_all(engine)
> >> > Base.metadata.create_all(engine)
> >> > Session = sessionmaker(engine)
> >> > session = Session()
> >> >
> >> >
> >> > session.query(Game).join(Game.year_stadium).all() # works
> >> > session.query(Game).options(joinedload(Game.year_stadium)) # fails
> >> >
> >> > In the example above, I'm trying to have a relationship to a table.
> It's not a classic association table example, since the third table needs
> one column from table 2 and one column from table 1 to be joined.
> >> > The relationship I wrote works well for simple joins or when
> lazy-loading, but fails with a joinedload.
> >> >
> >> > Is there a way to make it work ?
> >> >
> >> > --
> >> > 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 sqlalchemy+unsubscr...@googlegroups.com.
> >> > To post to this group, send email to sqlalchemy@googlegroups.com.
> >> > Visit this group at https://groups.google.com/group/sqlalchemy.
> >> > For more options, visit https://groups.google.com/d/optout.
> >>
> >> --
> >> 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 sqlalchemy+unsubscr...@googlegroups.com.
> >> To post to this group, send email to sqlalchemy@googlegroups.com.
> >> Visit this group at https://groups.google.com/group/sqlalchemy.
> >> For more options, visit https://groups.google.com/d/optout.
> >
> >
> >
> > --
> > Mehdi GMIRA
> > Lead Developer - RMPulse
> > Mail: mgm...@wiremind.fr
> > Mobile: +33 6 99 31 56 69
> > Wiremind SAS
> >
> > --
> > 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 sqlalchemy+unsubscr...@googlegroups.com.
> > To post to this group, send email to sqlalchemy@googlegroups.com.
> > Visit this group at https://groups.google.com/group/sqlalchemy.
> > For more options, visit https://groups.google.com/d/optout.
>
> --
> 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 sqlalchemy+unsubscr...@googlegroups.com.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> Visit this group at https://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/d/optout.
>


-- 
Mehdi GMIRA
Lead Developer - RMPulse
Mail: *mgm...@wiremind.fr <mgm...@wiremind.fr>*
Mobile: +33 6 99 31 56 69
Wiremind SAS

-- 
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 sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to