gpt4 book ai didi

python - 在 SQLAlchemy 中为 ORM 创建一对多关系

转载 作者:行者123 更新时间:2023-11-30 22:49:21 24 4
gpt4 key购买 nike

我正在学习 SQLAlchemy,今天我已经阅读了很多关于关系的文章,包括关于 SO 的多篇文章。然而,我发现没有一个例子能够很好地回答这个问题,尽管我认为这将是处理关系时首先要回答的问题之一。

我有网页表单数据,其中很多是重复的——比如访问者浏览器用户代理字符串、提供表单的域和提供表单的域。我想保留这些数据,但显然将代理之类的东西存储在他们自己的表中,然后在表单数据表中保留一个 ID 更有意义。所以我有一个这样的代理类:

class Agent(Base):
__tablename__ = 'agents'
__table_args__ = {'mysql_engine': 'InnoDB'}

ID = Column(Integer, autoincrement = True, primary_key = True)
UserAgent = Column(VARCHAR(256), nullable = False, unique = True)

#UniqueConstraint('UserAgent')

def __repr__(self):
return "<Agent(UserAgent='%s')>" % (self.UserAgent)

然后我有一个表单数据类:

class Lead(Base):
__tablename__ = 'leads'
__table_args__ = {'mysql_engine': 'InnoDB'}

ID = Column(String(32), primary_key = True)
AgentID = Column(Integer, ForeignKey('agents.ID'), nullable = False)
.... other non relational fields ....
IsPartial = Column(Boolean, nullable = False)

Agent = relationship('Agent', backref = backref('leads', uselist = True))

def __repr__(self):
return "<Lead(ID='%s')>" % (self.ID)

此时,SQLAlchemy 创建了我要求的所有表,我可以创建一个测试 Lead 实例:

testLead = Lead(ID='....', ...)

然后创建一个测试Agent实例:

testAgent = Agent(UserAgent='...', leads=testLead)

testLead 实例化得很好。但是,代理实例化失败:

TypeError: Incompatible collection type: Lead is not list-like

使用 testLead.Agent = [...] 结果:

AttributeError: 'list' object has no attribute '_sa_instance_state'

理想情况下,我希望能够使用 Agent 字符串实例化 Lead 对象。然后,当我使用 session.add 和 session.commit 让 ORM 将代理字符串添加到代理表中(如果丢失)。同样,当我实例化 Lead 类时,我希望能够使用:

lead = Lead(ID='...')

然后如果我使用:

lead.Agent

应该显示代理字符串。如果我正确阅读了文档,这将需要添加一些延迟加载设置。

有没有办法做到这一点?如果没有,我该如何修复上述错误?

谢谢

最佳答案

您似乎混合了 1-many 关系的两个方面:您的代码与测试数据的工作方式就好像一个 Lead 有许多 Agent,而relationship定义则相反。假设模型是正确的,下面应该有效:

testLead = Lead(ID='....', ...)
testAgent = Agent(UserAgent='...', leads=[testLead])

或:

testAgent = Agent(UserAgent='...')
testLead = Lead(ID='....', ..., Agent=testAgent)

至于你问题的第二部分,你可以用简单的python来实现:

class Lead(Base):
# ...

@property
def UserAgent(self):
return self.Agent and self.Agent.UserAgent

@UserAgent.setter
def UserAgent(self, value):
# @note: you might first want to search for agent with this UserAgent value,
# and create a new one only if one does not exist
# agent_obj = object_session(self).query(Agent).filter(Agent.UserAgent == value).one()
agent_obj = Agent(UserAgent=value)
self.Agent = agent_obj

@UserAgent.deleter
def UserAgent(self):
self.Agent = None

或者您可以使用 Association Proxy目的:

def _agent_find_or_create(user_agent):
agent = session.query(Agent).filter(Agent.UserAgent==user_agent).first()
return agent or Agent(UserAgent=user_agent)

class Lead(Base):
# ...

Agent = relationship('Agent', backref = backref('leads', uselist = True))
UserAgent = association_proxy('Agent', 'UserAgent',
creator=_agent_find_or_create)

关于python - 在 SQLAlchemy 中为 ORM 创建一对多关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28596296/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com