Python 跨文件的SQLAlchemy类

Python 跨文件的SQLAlchemy类,python,sqlalchemy,Python,Sqlalchemy,我正试图弄清楚如何让SQLAlchemy类分布在多个文件中,但我一生都不知道如何做到这一点。我对SQLAlchemy很陌生,所以如果这个问题很琐碎,请原谅我 将这3个类分别放在各自的文件中: A.py: from sqlalchemy import * from main import Base class A(Base): __tablename__ = "A" id = Column(Integer, primary_key=True) Bs = relatio

我正试图弄清楚如何让SQLAlchemy类分布在多个文件中,但我一生都不知道如何做到这一点。我对SQLAlchemy很陌生,所以如果这个问题很琐碎,请原谅我

将这3个类分别放在各自的文件中:

A.py:

from sqlalchemy import *
from main import Base

class A(Base):
    __tablename__ = "A"
    id  = Column(Integer, primary_key=True)
    Bs  = relationship("B", backref="A.id")
    Cs  = relationship("C", backref="A.id")
from sqlalchemy import *
from main import Base

class B(Base):
    __tablename__ = "B"
    id    = Column(Integer, primary_key=True)
    A_id  = Column(Integer, ForeignKey("A.id"))
from sqlalchemy import *
from main import Base

class C(Base):
    __tablename__ = "C"    
    id    = Column(Integer, primary_key=True)
    A_id  = Column(Integer, ForeignKey("A.id"))
B.py:

from sqlalchemy import *
from main import Base

class A(Base):
    __tablename__ = "A"
    id  = Column(Integer, primary_key=True)
    Bs  = relationship("B", backref="A.id")
    Cs  = relationship("C", backref="A.id")
from sqlalchemy import *
from main import Base

class B(Base):
    __tablename__ = "B"
    id    = Column(Integer, primary_key=True)
    A_id  = Column(Integer, ForeignKey("A.id"))
from sqlalchemy import *
from main import Base

class C(Base):
    __tablename__ = "C"    
    id    = Column(Integer, primary_key=True)
    A_id  = Column(Integer, ForeignKey("A.id"))
C.py:

from sqlalchemy import *
from main import Base

class A(Base):
    __tablename__ = "A"
    id  = Column(Integer, primary_key=True)
    Bs  = relationship("B", backref="A.id")
    Cs  = relationship("C", backref="A.id")
from sqlalchemy import *
from main import Base

class B(Base):
    __tablename__ = "B"
    id    = Column(Integer, primary_key=True)
    A_id  = Column(Integer, ForeignKey("A.id"))
from sqlalchemy import *
from main 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.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, backref, sessionmaker

Base = declarative_base()

import A
import B
import C

engine = create_engine("sqlite:///test.db")
Base.metadata.create_all(engine, checkfirst=True)
Session = sessionmaker(bind=engine)
session = Session()

a  = A.A()
b1 = B.B()
b2 = B.B()
c1 = C.C()
c2 = C.C()

a.Bs.append(b1)
a.Bs.append(b2)    
a.Cs.append(c1)
a.Cs.append(c2)    
session.add(a)
session.commit()
/project/models/

__init__.py contains

from project.models.a import A 
from project.models.b import B
etc...
上面给出了错误:

sqlalchemy.exc.NoReferencedTableError: Foreign key assocated with column 'C.A_id' could not find table 'A' with which to generate a foreign key to target column 'id'
如何在这些文件中共享声明性基础

考虑到我可能会在上面扔一些类似塔架或涡轮齿轮的东西,实现这一点的“正确”方法是什么

编辑2011年3月10日


我从金字塔框架中找到了描述问题的描述,更重要的是验证了这是一个实际问题,而不仅仅是我困惑的自我,这才是问题所在。希望它能帮助那些敢于走这条危险道路的人:)

解决您问题的最简单方法是从导入
A
B
C
的模块中取出
Base
;打破循环导入

base.py a、 派克 b、 派克 c、 派克 main.py 在我的机器上工作:

$ python main.py ; echo $?
0

我使用的是Python 2.7+Flask 0.10+SQLAlchemy 1.0.8+Postgres 9.4.4.1

此样板配置了一个用户和用户详细信息模型,该模型存储在“用户”模块的同一文件“models.py”中。这些类都继承自SQLAlchemy基类

我添加到项目中的所有附加类也都是从这个基类派生的,随着models.py文件的增大,我决定将models.py文件拆分为每个类一个文件,并遇到了这里描述的问题

我发现的解决方案与@computermacgyver 2013年10月23日的帖子一样,是将我所有的类包含到我创建的新模块的init.py文件中,以保存所有新创建的类文件。看起来像这样:

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, backref, sessionmaker

Base = declarative_base()

import A
import B
import C

engine = create_engine("sqlite:///test.db")
Base.metadata.create_all(engine, checkfirst=True)
Session = sessionmaker(bind=engine)
session = Session()

a  = A.A()
b1 = B.B()
b2 = B.B()
c1 = C.C()
c2 = C.C()

a.Bs.append(b1)
a.Bs.append(b2)    
a.Cs.append(c1)
a.Cs.append(c2)    
session.add(a)
session.commit()
/project/models/

__init__.py contains

from project.models.a import A 
from project.models.b import B
etc...

如果我可以补充一下我的感觉,因为我也有同样的问题。在创建
Base
表之后,需要在创建
Base=declarative\u Base()
的文件中导入类。如何设置我的项目的简短示例:

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')
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'))
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
型号/预算.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')
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'))
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
model/\uuuu init\uuuuu.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')
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'))
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

对我来说,在
app.tool.tool\u实体中添加
import app.tool.tool\u entity
从app.tool.tool\u entity导入工具中添加
就足以创建表。不过,我还没有尝试添加关系

文件夹结构:

app/
  app.py
  tool/
    __init__.py
    tool_entity.py
    tool_routes.py
#app/tool/tool_entity.py
从app.base导入base
从sqlalchemy导入列,整数,字符串
类工具(基本):
__tablename_uu='tool'
id=列(整数,主键=True)
名称=列(字符串,可空=False)
fullname=列(字符串)
fullname2=列(字符串)
昵称=列(字符串)
定义报告(自我):
返回“”%(
self.name、self.fullname、self.昵称)
#app/tool/_uinit.py
从app.tool.tool\u实体导入工具
#app/app.py
从烧瓶进口烧瓶
从sqlalchemy导入创建引擎
从app.tool.tool_路径导入工具_蓝图
从app.base导入base
db_方言='postgresql'
db_user='postgres'
db_pwd='postgrespwd'
db_host='db'
db_名称='db_名称'
引擎=创建引擎(f'{db_方言}://{db_用户}:{db_pwd}@{db_主机}/{db_名称},echo=True)
Base.metadata.create_all(引擎)
app=烧瓶(名称)
@应用程序路径(“/”)
def hello_world():
返回“你好,世界”
应用程序注册蓝图(工具蓝图,url前缀='/tool')
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
#当调试(监视模式)打开时,您可以在此处或文件中的任何其他位置添加此导入,
#保存此文件后,应立即创建该表。
导入app.tool.tool\u实体
app.run(主机=0.0.0.0',端口=5000,调试=True)

@S.Lott如果所有类都在一个文件中,则上述操作有效,因此您告诉我:)您的代码没有给出此错误,请发布包含实际错误的代码。修复导入,使其运行,以便有人能够真正看到您的错误。@S.Lott我的困惑显然集中在如何避免循环导入。我来自C语言,这不是一个问题。我很抱歉占用了你的时间。@joveha:什么?您遇到的这些循环导入问题是什么。请发布带有循环导入的代码,以便我们解释如何分解它们并避免循环。这些评论中有太多模糊的假设。你有什么问题?请具体说明。使用
scoped_session
@user:session处理与本文中的问题无关,这确实是一个简单的老python问题(如何导入内容?);但既然我已经引起了您的注意,我强烈建议不要使用
作用域会话
,除非您知道为什么需要线程本地存储;使用
scoped_session
的问题在于,它很容易导致事务泄漏和数据过时,在可能发生这种情况时,代码中没有指向该点的明确链接。这种设计模式似乎不适用于python3。是否有任何与python3兼容的简单修复程序?@computermacgyver:此模式应该可以在不同的python版本中正常工作。请提出一个新问题,这样您就可以包含所有代码以及您看到的错误。谢谢@dequestarmappartialsettr。我发现只有当我尝试将a.py、b.py、c.py和model.py放入一个单独的模块时,才会发生错误。我发现在这种情况下的解决方案是将base.py代码包含在模块的_init__u;.py文件中。我已经把它放好了。谢谢你的回复。你为什么认为你需要使用Flask?只有在Python中才有必要这样做,但我认为这是一种非常优雅的方式来避开一些棘手的问题。唯一的区别是我需要做