SQLAlchemy classes across files
The simplest solution to your problem will be to take Base
out of the module that imports A
, B
and C
; Break the cyclic import.
base.py
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
a.py
from sqlalchemy import *
from base import Base
from sqlalchemy.orm import relationship
class A(Base):
__tablename__ = "A"
id = Column(Integer, primary_key=True)
Bs = relationship("B", backref="A.id")
Cs = relationship("C", backref="A.id")
b.py
from sqlalchemy import *
from base import Base
class B(Base):
__tablename__ = "B"
id = Column(Integer, primary_key=True)
A_id = Column(Integer, ForeignKey("A.id"))
c.py
from sqlalchemy import *
from base import Base
class C(Base):
__tablename__ = "C"
id = Column(Integer, primary_key=True)
A_id = Column(Integer, ForeignKey("A.id"))
main.py
from sqlalchemy import create_engine
from sqlalchemy.orm import relationship, backref, sessionmaker
import base
import a
import b
import c
engine = create_engine("sqlite:///:memory:")
base.Base.metadata.create_all(engine, checkfirst=True)
Session = sessionmaker(bind=engine)
session = Session()
a1 = a.A()
b1 = b.B()
b2 = b.B()
c1 = c.C()
c2 = c.C()
a1.Bs.append(b1)
a1.Bs.append(b2)
a1.Cs.append(c1)
a1.Cs.append(c2)
session.add(a1)
session.commit()
Works on my machine:
$ python main.py ; echo $?
0
If I may add my bit of sense as well since I had the same problem. You need to import the classes in the file where you create the Base = declarative_base()
AFTER you created the Base
and the Tables
. Short example how my project is set up:
model/user.py
from sqlalchemy import *
from sqlalchemy.orm import relationship
from model import Base
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
budgets = relationship('Budget')
model/budget.py
from sqlalchemy import *
from model import Base
class Budget(Base):
__tablename__ = 'budget'
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('user.id'))
model/__init__.py
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
_DB_URI = 'sqlite:///:memory:'
engine = create_engine(_DB_URI)
Base = declarative_base()
Base.metadata.create_all(engine)
DBSession = sessionmaker(bind=engine)
session = DBSession()
from .user import User
from .budget import Budget
I'm using Python 2.7 + Flask 0.10 + SQLAlchemy 1.0.8 + Postgres 9.4.4.1
This boilerplate comes configured with a User and UserDetail models stored in the same file "models.py" in the "user" module. These classes both inherit from an SQLAlchemy base class.
All of the additional classes I've added to my project also derived from this base class, and as the models.py file grew larger, I decided to split the models.py file into one file per class, and ran into the problem described here.
The solution I found, along the same lines as @computermacgyver's Oct 23 2013 post, was to include all my classes to the init.py file of the new module I created to hold all the newly created class files. Looks like this:
/project/models/
__init__.py contains
from project.models.a import A
from project.models.b import B
etc...