跨文件的SQLAlchemy类

jov*_*eha 68 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  = relationship("B", backref="A.id")
    Cs  = relationship("C", backref="A.id")
Run Code Online (Sandbox Code Playgroud)

B.py:

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"))
Run Code Online (Sandbox Code Playgroud)

C.py:

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"))
Run Code Online (Sandbox Code Playgroud)

然后说我们有一个像这样的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()
Run Code Online (Sandbox Code Playgroud)

以上给出了错误:

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'
Run Code Online (Sandbox Code Playgroud)

如何跨这些文件共享声明性基础?

什么是"正确"的方法来实现这一点,考虑到我可能会抛出像PylonsTurbogears这样的东西?

编辑10-03-2011

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

Sin*_*ion 74

解决问题的最简单方法是Base取出导入的模块A,B并且C; 打破循环导入.

base.py

from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
Run Code Online (Sandbox Code Playgroud)

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")
Run Code Online (Sandbox Code Playgroud)

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"))
Run Code Online (Sandbox Code Playgroud)

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"))
Run Code Online (Sandbox Code Playgroud)

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()
Run Code Online (Sandbox Code Playgroud)

适用于我的机器:

$ python main.py ; echo $?
0
Run Code Online (Sandbox Code Playgroud)

  • @user:会话处理与这篇文章中的问题无关,这实际上是一个普通的老python问题(我如何导入东西?); 但是既然我已经引起了你的注意,我建议*强烈反对*使用`scoped_session`,除非你知道为什么你需要线程本地存储; 使用`scoped_session`的问题在于,它可以很容易地结束泄漏的事务和过时的数据,并且在可能发生的情况下没有明确链接到代码中的点. (3认同)
  • 从遥远的未来发帖,汽车是由激光制成的,这个答案仍然相关/有用。感谢您提供了很棒的代码示例——这正是我想要做的,但在输入 SEO 友好的搜索词时遇到了困难。 (2认同)

小智 8

我正在使用Python 2.7 + Flask 0.10 + SQLAlchemy 1.0.8 + Postgres 9.4.4.1

该样板配置有User和UserDetail模型,这些模型存储在"user"模块中的同一文件"models.py"中.这些类都继承自SQLAlchemy基类.

我添加到项目中的所有其他类也派生自此基类,并且随着models.py文件变大,我决定将models.py文件拆分为每个类的一个文件,并遇到所描述的问题这里.

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

/project/models/

__init__.py contains

from project.models.a import A 
from project.models.b import B
etc...
Run Code Online (Sandbox Code Playgroud)

  • 为什么你认为你需要使用 Flask? (2认同)

Pet*_*ter 7

如果我也遇到同样的问题,我也可以增加一点理智。您需要导入,你创建的文件中的类Base = declarative_base()创建的AFTER BaseTables。简短示例如何设置我的项目:

型号/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')
Run Code Online (Sandbox Code Playgroud)

型号/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'))
Run Code Online (Sandbox Code Playgroud)

型号/__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
Run Code Online (Sandbox Code Playgroud)

  • 只有在 Python 中才需要这样的东西,但我认为这是一种非常优雅的方式来绕过一些麻烦。唯一的区别是我需要做“from”。import Base` 而不是 `from model import Base` (2认同)