【发布时间】:2014-02-24 16:35:56
【问题描述】:
我在 postgresql 中有两张表,一张名为 ip_address,另一张名为 network。
ip_address 表有两列:
-
id是INTEGER -
v4address是INET
network 表有两列:
-
id是INTEGER -
v4representation是CIDR
我希望能够选择一个ip_address 并急切地加载ip_addresses network(s),而不必在表之间定义一个基于id 的外键关系。 id 列由与其他表的其他不相关关系使用。
完成此操作的 SQL 是:
select * from ip_address join network on ip_address.v4address << network.v4representation;
在 postgresql 中,<< 运算符可用于比较 INET 和 CIDR。它将匹配INET 包含在CIDR 中的行。
我可以在我的 IPAddress 模型上定义一个 property 来完成此操作:
@property
def networks(self):
query = session.query(Network)
query = query.filter("v4representation >> :v4addr").params(v4addr=self.v4address)
return query.all()
这可行,但是当我实际尝试在应用程序中使用此property 时,我遇到了典型的“N + 1”查询问题。我想以一种能够急切加载 ip 地址网络的方式来定义它。
我尝试使用primaryjoin 将其定义为relationship,但不知道需要什么。我试过这个:
networks = db.relationship("Network",
primaryjoin='IPAddress.v4address << Network.v4representation',
viewonly=True)
但是 sqlalchemy 不知道如何处理 << 运算符,所以我切换到了这个:
networks = db.relationship("Network",
primaryjoin='IPAddress.v4address.op("<<")(Network.v4representation)',
viewonly=True)
但是 sqlalchemy 会抛出一个ArgumentError:
ArgumentError: Could not locate any relevant foreign key columns for primary join condition 'public.ip_address.v4address << public.network.v4representation' on relationship IPAddress.networks. Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or are annotated in the join condition with the foreign() annotation.
我尝试了几种为relationship 定义foreign_key 的组合:
networks = db.relationship("Network",
primaryjoin='IPAddress.v4address.op("<<")(Network.v4representation)',
foreign_keys='[Network.v4representation]',
viewonly=True)
但是 sqlalchemy 抛出 ArgumentErrors:
ArgumentError:关系 IPAddress.networks 无法根据连接条件和 remote_side 参数确定任何明确的本地/远程列对。考虑使用 remote() 注释来准确标记连接条件中位于关系远程端的那些元素。
将IPAddress.v4address 或Network.v4representation 指定为remote_side 都不会更改异常。
尝试使用foreign/remote 注释primaryjoin 条件也没有任何帮助。
回到我最初的意图,我希望能够执行一个查询,该查询将返回 IP 地址并急切加载他们的网络(可能还有来自网络其他关系的数据,因为这是我的完整架构的简化)。
有人有什么建议吗?
提前致谢。
【问题讨论】:
标签: python postgresql sqlalchemy