I'm trying to write Schedule class which contains records like this: ... session, base, engine declaration somewhere here...
class Schedule(Base):
__tablename__ = 'schedule'
id = Column(Integer, primary_key=True)
# and here i need ref to Station class
station_id = Column(Integer, ForeignKey('station.id'))
station = relationship('Station') # Also tried Station
arr_time = Column(Time)
def __init__(self, station_name, arrive_time):
self.metadata.create_all()
self.arrive_time = arrive_time
# And now I'm trying to find station object by a given name
# and add ref to it in self.station.
# The selection of a station works properly here:
station = session.query(Station).filter(Station.name == station_name).first()
# But on this statement I get an error: None object has no method 'append'
self.station.append(station)
session.add(self)
session.commit()
After that I implement class 'Station'
class Station(Base):
__tablename__ = 'stations'
id = Column(Integer, primary_key=True)
name = Column(String)
def __init__(self, name):
self.name = name
So, when I'm trying to add new Schedule record I get an error:
AttributeError: 'NoneType' object has no attribute 'append'
The one-to-many case (where the foreign key in the first class and relationsip in the second one) works correctly.
What's wrong with my code?
Update: Also tried example from documentation:
engine = create_engine('sqlite:///:memory:')
Base = declarative_base(engine)
session = sessionmaker(bind=engine)()
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
child_id = Column(Integer, ForeignKey('child.id'))
child = relationship("Child")
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
if __name__ == '__main__':
Base.metadata.create_all()
parent = Parent()
session.add(parent)
child = Child()
session.add(child)
print(hasattr(Parent, 'child'))
print(hasattr(parent, 'child'))
print(type(Parent.child))
print(type(parent.child))
I get:
>>> True
>>> True
>>> <class 'sqlalchemy.orm.attributes.InstrumentedAttribute'>
>>> <class 'NoneType'>
I've got it))
The problem was that as default uselist
flag in constructor of relationship is set for True
.
But - I don't really understand why it is not written in documentation - in the case of many-to-one relation this flag is set for False
.
So, to solve my problem I simply have to change this:
station = relationship("Station", uselist=True)
or use in constructor:
self.station = station
This completely solves my problem.
I had a similar issue. I think the problem is that the relationship does not get triggered until you add and commit.
engine = create_engine('sqlite:///:memory:')
Base = declarative_base(engine)
session = sessionmaker(bind=engine)()
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
child_id = Column(Integer, ForeignKey('child.id'))
child = relationship("Child")
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
if __name__ == '__main__':
Base.metadata.create_all()
parent = Parent()
session.add(parent)
child = Child()
session.add(child)
session.commit() # IMPORTANT: this is necessary for relationship to work
print(hasattr(Parent, 'child'))
print(hasattr(parent, 'child'))
print(type(Parent.child))
print(type(parent.child))
The only line I added is
session.commit() # IMPORTANT: this is necessary for relationship to work
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With