【发布时间】:2016-05-03 00:03:34
【问题描述】:
根据我对 SQLAlchemy 的理解,为了向会话中添加模型,I need to call session.add(obj)。但是,出于某种原因,在我的代码中,SQLAlchemy 似乎会自动执行此操作。
为什么会这样,我该如何阻止它?我是否以正确的方式接近会议?
示例
>>> from database import Session as db
>>> import clients
>>> from instances import Instance
>>> from uuid import uuid4
>>> len(db.query(Instance).all())
>>> 0 # Note, no instances in database/session
>>> i = Instance(str(uuid4()), clients.get_by_code('AAA001'), [str(uuid4())])
>>> len(db.query(Instance).all())
>>> 1 # Why?? I never called db.add(i)!
database.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy.ext.declarative import declarative_base
import config
Base = declarative_base()
class Database():
def __init__(self):
db_url = 'postgresql://{:s}:{:s}@{:s}:{}/{:s}'.format(
config.database['user'],
config.database['password'],
config.database['host'],
config.database['port'],
config.database['dbname']
)
self.engine = create_engine(db_url)
session_factory = sessionmaker(bind=self.engine)
self.session = scoped_session(session_factory)
Database = Database()
Session = Database.session
instance.py
from sqlalchemy import Column, Text, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.dialects.postgresql import UUID, ARRAY
import database
Base = database.Base
class Instance(Base):
__tablename__ = 'instances'
uuid = Column(UUID, primary_key=True)
client_code = Column(
Text, ForeignKey('clients.code', ondelete='CASCADE'), nullable=False)
mac_addresses = Column(ARRAY(Text, as_tuple=True),
primary_key=True)
client = relationship("Client", back_populates="instances")
def __init__(self, uuid, client, mac_addresses):
self.uuid = uuid
self.client = client
self.mac_addresses = tuple(mac_addresses)
client.py
from sqlalchemy import Column, Text
from sqlalchemy.orm import relationship
import database
from database import Session as db
Base = database.Base
class Client(Base):
__tablename__ = 'clients'
code = Column(Text, primary_key=True)
name = Column(Text)
instances = relationship("Instance", back_populates='client')
def __init__(self, code, name=None):
self.code = code
self.name = name
def get_by_code(code):
client = db.query(Client).filter(Client.code == code).first()
return client
【问题讨论】:
-
我不认为添加到会话中的实例是新创建的对象。我怀疑它是由
clients.get_by_code('AAA001')加载的Client的实例 -
Client的实例肯定不应该由对Instances的查询返回?查询是db.query(Instance).all()而不是db.query(Client).all()所以我不希望在响应中得到任何Client对象。 -
也就是说,我有点找到了“问题”的根源。 SQLAlchemy 将
Instance对象添加到会话中的原因是关系中的back_populates。如果我不添加back_populates。db.query(Instances).all()按我的预期返回一个空列表。这样做的副作用是关系不能很好地工作,因为它不会将Client实例加载到会话中,并且您不能使用instance.client来加载相关对象。我已经停止使用 SQLAlchemy 的映射器,因为它给我带来了太多麻烦,但希望这对其他人有帮助。
标签: python session sqlalchemy