Python SQLAlchemy,即时加载postgresql INET/CIDR关系
我在postgresql中有两个表,一个名为ip_address,另一个名为network ip_地址表有两列: id是一个整数 v4address是一个INET 网络表有两列: id是一个整数 这是一个CIDR 我希望能够选择ip_地址并急切地加载ip_地址网络,而不必在表之间定义基于id的外键关系。id列由其他与其他表无关的关系使用 实现这一点的SQL是:Python SQLAlchemy,即时加载postgresql INET/CIDR关系,python,postgresql,sqlalchemy,Python,Postgresql,Sqlalchemy,我在postgresql中有两个表,一个名为ip_address,另一个名为network ip_地址表有两列: id是一个整数 v4address是一个INET 网络表有两列: id是一个整数 这是一个CIDR 我希望能够选择ip_地址并急切地加载ip_地址网络,而不必在表之间定义基于id的外键关系。id列由其他与其他表无关的关系使用 实现这一点的SQL是: select * from ip_address join network on ip_address.v4address <&l
select * from ip_address join network on ip_address.v4address << network.v4representation;
这是可行的,但当我实际尝试在应用程序中使用此属性时,我会遇到典型的N+1查询问题。我想用这样一种方式来定义它,以便能够在网络中急切地加载ip地址
我曾尝试使用primaryjoin将其定义为一种关系,但不知道需要什么。我试过这个:
networks = db.relationship("Network",
primaryjoin='IPAddress.v4address << Network.v4representation',
viewonly=True)
我尝试了几种为关系定义外键的组合:
但是sqlalchemy抛出了错误:
ArgumentError:关系IPAddress.networks无法根据连接条件和远程参数确定任何明确的本地/远程列对。考虑使用远程注释来准确地标记关系的远程侧的连接条件的元素。
将IPAddress.v4address或Network.v4representation指定为远程\u端都不会更改异常
用foreign/remote注释primaryjoin条件的尝试也没有帮助
回到我最初的意图,我希望能够执行一个查询,该查询将返回ip地址并立即加载他们的网络以及可能来自网络和其他关系的数据,因为这是我的完整模式的简化
有人有什么建议吗
提前感谢。这里缺少的一点是,自定义操作符没有在关系框架内工作。为了在这种情况下提供帮助,我为SQLAlchemy 0.9.2添加了一个新特性,它是is_比较标志,下面是一个示例,位于 以下是一个使用较少的公共API实现相同结果的版本,该版本也适用于0.8:
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.dialects.postgresql import INET, CIDR
Base = declarative_base()
# workaround before 0.9.2
from sqlalchemy.sql import operators
is_contained_by = operators.custom_op("<<")
operators._comparison.add(is_contained_by)
class IPA(Base):
__tablename__ = 'ip_address'
id = Column(Integer, primary_key=True)
v4address = Column(INET)
network = relationship("Network",
primaryjoin=lambda: is_contained_by(
IPA.v4address,
(foreign(Network.v4representation))
),
viewonly=True
)
class Network(Base):
__tablename__ = 'network'
id = Column(Integer, primary_key=True)
v4representation = Column(CIDR)
print Session().query(IPA).join(IPA.network)
在0.9.2及更高版本中,可按以下方式进行:
class IPA(Base):
__tablename__ = 'ip_address'
id = Column(Integer, primary_key=True)
v4address = Column(INET)
network = relationship("Network",
primaryjoin="IPA.v4address.op('<<', is_comparison=True)"
"(foreign(Network.v4representation))",
viewonly=True
)
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.
networks = db.relationship("Network",
primaryjoin='IPAddress.v4address.op("<<")(Network.v4representation)',
foreign_keys='[Network.v4representation]',
viewonly=True)
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.dialects.postgresql import INET, CIDR
Base = declarative_base()
# workaround before 0.9.2
from sqlalchemy.sql import operators
is_contained_by = operators.custom_op("<<")
operators._comparison.add(is_contained_by)
class IPA(Base):
__tablename__ = 'ip_address'
id = Column(Integer, primary_key=True)
v4address = Column(INET)
network = relationship("Network",
primaryjoin=lambda: is_contained_by(
IPA.v4address,
(foreign(Network.v4representation))
),
viewonly=True
)
class Network(Base):
__tablename__ = 'network'
id = Column(Integer, primary_key=True)
v4representation = Column(CIDR)
print Session().query(IPA).join(IPA.network)
class IPA(Base):
__tablename__ = 'ip_address'
id = Column(Integer, primary_key=True)
v4address = Column(INET)
network = relationship("Network",
primaryjoin="IPA.v4address.op('<<', is_comparison=True)"
"(foreign(Network.v4representation))",
viewonly=True
)